Tusiapedia tusiapediawiki https://tusiapedia.miraheze.org/wiki/Main_Page MediaWiki 1.40.2 first-letter Media Special Talk User User talk Tusiapedia Tusiapedia talk File File talk MediaWiki MediaWiki talk Template Template talk Help Help talk Category Category talk Module Module talk Template:T 10 59 116 2016-09-06T23:14:40Z star>Alistair3149 0 Protected "[[Template:T]]": Completed template, changes can be proposed in the talk page ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) wikitext text/x-wiki <includeonly><nowiki>{{</nowiki>[[Template:{{{1}}}|{{{1}}}]]{{t/piece|{{{2|---}}}}}{{t/piece|{{{3|---}}}}}{{t/piece|{{{4|---}}}}}{{t/piece|{{{5|---}}}}}{{t/piece|{{{6|---}}}}}{{t/piece|{{{7|---}}}}}{{t/piece|{{{8|---}}}}}{{t/piece|{{{9|---}}}}}{{t/piece|{{{10|---}}}}}{{t/piece|{{{11|---}}}}}{{t/piece|{{{12|---}}}}}{{t/piece|{{{13|---}}}}}{{t/piece|{{{14|---}}}}}{{t/piece|{{{15|---}}}}}{{t/piece|{{{16|---}}}}}{{t/piece|{{{17|---}}}}}{{t/piece|{{{18|---}}}}}{{t/piece|{{{19|---}}}}}{{t/piece|{{{20|---}}}}}{{t/piece|{{{21|---}}}}}<nowiki>}}</nowiki></includeonly><noinclude> {{documentation}}</noinclude> 9bbfbb3d891ffa62ccebed3d5790ccf39d59c793 Category:Article management templates 14 4 6 2017-03-31T21:26:53Z Star>Alistair3149 0 wikitext text/x-wiki A list of article management templates [[Category:Templates]] 11b8b439968d60cbb1df76388c0e1e9b122ad13c Category:File management templates 14 10 18 2017-03-31T21:27:26Z Star>Alistair3149 0 wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Citation templates 14 7 12 2017-03-31T21:29:04Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:General wiki templates 14 12 22 2017-03-31T21:32:04Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Infobox Templates 14 15 28 2017-03-31T21:32:56Z Star>Alistair3149 0 wikitext text/x-wiki See [[Help:Infoboxes]] [[Category:Templates]] 50fb8af8e4d62b8e888bb9246e15a1806c52b2b5 Category:Mathematical function templates 14 24 46 2017-04-26T22:37:58Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Typing-aid templates 14 35 68 2017-04-27T22:33:25Z Star>Alistair3149 0 wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Formatting and function templates 14 11 20 2017-04-27T23:10:59Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Internal link templates 14 18 34 2017-04-27T23:24:07Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Template:Nbsp 10 44 86 2017-04-27T23:27:42Z Star>Alistair3149 0 Redirected page to [[Template:Spaces]] wikitext text/x-wiki #REDIRECT [[Template:Spaces]] d55076009c86bad01caacd67c545037409e5e1ee Category:String manipulation templates 14 31 60 2017-06-03T16:34:09Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Manual templates 14 23 44 2017-06-15T21:41:20Z Star>Alistair3149 0 Alistair3149 moved page [[Category:Live templates]] to [[Category:Manual templates]] wikitext text/x-wiki Below are WIP templates that require manual update frequently as of now, and they are pending to be automated in the future. [[Category:Templates]] 6b82ad760e14f78fdd70dc3f3d47ab254e57ff36 Category:SEO templates 14 29 56 2017-06-19T03:29:57Z Star>Alistair3149 0 wikitext text/x-wiki One of these templates should be included in all page in the main namespace [[Category:Templates]] 0a8943c2a2dbff16b4685086e66c2086c7d39367 Category:Vehicle Specification Templates 14 38 74 2017-11-01T19:19:06Z Star>Alistair3149 0 added category wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Substitution only templates 14 32 62 2017-11-01T19:35:10Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Audio templates 14 5 8 2018-06-02T05:16:24Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:I18n templates 14 14 26 2019-12-08T19:56:48Z Star>Alistair3149 0 Cleaned up translation residue wikitext text/x-wiki '''I18n templates''' are templates contain repetitive words used in the whole wiki. The following templates help to reduce redundancy in translations and also serve as the standard translation for frequently used words. [[Category:Templates]] 7717381b16fc84d004cf6f5bdaa73fa9febd0b07 Category:Language templates 14 19 36 2019-12-08T22:59:13Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:DPL templates 14 8 14 2020-03-12T23:04:47Z Star>Alistair3149 0 wikitext text/x-wiki This category contains templates which are designed solely for use with [https://help.gamepedia.com/Extension:DPL3/Manual DynamicPageList3]. For all page that uses DPL calls, see [[Special:WhatLinksHere/Template:Extension DPL]]. [[Category:Templates]] 2bb614cfa9d61ac951d5b671ebaa9bfbbd6fed0c Category:Lua-based templates 14 20 38 2020-03-15T08:59:34Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Under-construction templates 14 36 70 2020-03-17T19:54:09Z Star>Alistair3149 0 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Alien language templates 14 3 4 2020-03-17T19:54:36Z Star>Alistair3149 0 1 revision imported wikitext text/x-wiki This category contains templates related displaying alien languages in article. [[Category:Templates]] 31028d351947fb2c12f3d3976ef9be10d8ccdd76 Category:Infobox templates 14 16 30 2020-03-17T19:54:36Z Star>Alistair3149 0 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Maintenance templates 14 22 42 2020-03-17T19:54:36Z Star>Alistair3149 0 1 revision imported wikitext text/x-wiki This category contains templates related to ones that are used in articles that require maintenance. [[Category:Templates]] 258ee9e751f38daed5ebb5a2281fa0f03311d340 Category:Templates imported from Wikipedia 14 33 64 2020-03-17T19:54:36Z Star>Alistair3149 0 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Vehicle specification templates 14 39 76 2020-03-17T19:54:36Z Star>Alistair3149 0 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Template:Spaces 10 45 88 2020-03-17T20:29:07Z Star>Alistar Bot 0 /* top */Hygiene, replaced: {{documentation}} → {{/doc}} wikitext text/x-wiki <span class="nowrap">{{#iferror:{{#expr:{{{1|1}}}}} |{{#switch:{{{1}}} |fig=&#8199; |en=&ensp; |em=&emsp; |thin=&thinsp; |hair=&#8202; |&nbsp; }} |{{#invoke:String|rep|{{#switch:{{{2}}} |fig=&#8199; |en=&ensp; |em=&emsp; |thin=&thinsp; |hair=&#8202; |&nbsp; }}|{{{1|1}}}}} }}</span><noinclude> {{/doc}} </noinclude> 17efb36433f45a5c4f23528902387edcf0e174f0 Template:T/piece 10 60 118 2020-03-17T20:33:48Z star>Alistar Bot 0 /* top */Hygiene, replaced: {{documentation}} → {{/doc}} wikitext text/x-wiki {{#ifeq: {{{1|---}}}|---||&#124;<font color="gray">''&lt;{{{1}}}&gt;''</font>}}<noinclude> {{/doc}}</noinclude> 2ddf7df2334b2a1624bf213ade67ba6b68296e86 Template:Documentation 10 52 102 2020-03-19T00:32:09Z star>Alistair3149 0 wikitext text/x-wiki <includeonly>{{#invoke:Documentation|doc}}__NOEDITSECTION__{{#seo: |type = website |description = {{FULLPAGENAME}} is a template page used on the Star Citizen Wiki. Templates are pages that are embedded (transcluded) into other pages to allow for the repetition of information. |site_name = Star Citizen Wiki |locale = {{PAGELANGUAGE}} }}</includeonly><noinclude>{{/doc}}</noinclude> 2690a5347936db4ace54fe94a0b3092b6bb04a37 Category:Utility templates 14 37 72 2020-04-25T07:48:02Z Star>Alistair3149 0 wikitext text/x-wiki {{Category header|templates|that are not suitable to use directly on pages. They should only be used in templates|related=no}} [[Category:Templates]] 8ef6eadc680eea4f36a48b5fbf988cab1768b2ef Category:Interface message templates 14 17 32 2020-06-25T09:43:05Z Star>Alistair3149 0 Created page with "{{Category header|templates|MediaWiki interface messages}} [[Category:Templates]]" wikitext text/x-wiki {{Category header|templates|MediaWiki interface messages}} [[Category:Templates]] 2ceb3a9c4b6b1e027d79edc01030738d73250add Category:Number templates 14 26 50 2021-03-30T02:16:36Z Star>Alistair3149 0 Created page with "{{Category header|templates|manipulate number string}} [[Category:Templates]]" wikitext text/x-wiki {{Category header|templates|manipulate number string}} [[Category:Templates]] 8767a5b6f92ac0662e9e3feae33c87ecc776d542 Category:Numerical conversion templates 14 27 52 2021-03-30T02:16:59Z Star>Alistair3149 0 Created page with "{{Category header|templates|convert numbers}} [[Category:Templates]]" wikitext text/x-wiki {{Category header|templates|convert numbers}} [[Category:Templates]] 8d11e0ccdfed85c0343603873eb362298ca75a25 Module:DPLlua 828 54 106 2021-05-09T04:14:59Z star>Alistair3149 0 Sync with RS wiki Scribunto text/plain -- <nowiki> local dpl = {} local libraryUtil = require( 'libraryUtil' ) local hasContent = require( 'Module:Paramtest' ).has_content local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg dpl.pipe = '¦' local dataContentMarker = '`#@@#`' local allIncludedParamNames = {} -- Custom function for splitting a string because mw.text.split() is waaay too slow local function split( str, pattern, plain ) local res = {} local continue = true local startIndex = 1 while continue do local i, j = string.find( str, pattern, startIndex, plain ) if i then table.insert( res, string.sub( str, startIndex, i-1 ) ) startIndex = j + 1 else table.insert( res, string.sub( str, startIndex ) ) continue = false end end return res end -- Also custom function for speed local function trim( str ) return (string.gsub( str, '^%s+', '' ):gsub( '%s+$', '' )) end local function mergeItem( tbl, key, item ) if type( tbl[key] ) == 'table' and type( item ) == 'table' then for k in pairs( tbl[key] ) do mergeItem( tbl[key], k, item[k] ) end elseif type( tbl[key] ) == 'table' then table.insert( tbl[key], item ) else tbl[key] = { tbl[key], item } end end local escapeChars = { ['{'] = '&#123;', ['}'] = '&#125;', ['['] = '&#91;', [']'] = '&#93;', ['|'] = '&#124;', ['-'] = '&#8208;' } local function escape( str ) return (string.gsub( str, '[{}%[%]|%-]', escapeChars )) end local unEscapeChars = { ['&#123;'] = '{', ['&#125;'] = '}', ['&#91;'] = '[', ['&#93;'] = ']', ['&#124;'] = '|', ['&#8208;'] = '-' } local function unEscape( str ) return (string.gsub( str, '&#%d+;', unEscapeChars )) end local function fixCurlyBrackets( str ) -- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so -- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow. return (string.gsub( str, '\226\157[\180\181]', { ['❴'] = '{', ['❵'] = '}' } )) end local function removeFormattingSettings( query ) local toRemove = { 'mode', 'table', 'tablerow', 'tablesortcol', 'headingmode', 'headingcount', 'listattr', 'itemattr', 'hlistattr', 'hitemattr', 'userdateformat', 'shownamespace', 'escapelinks', 'titlemaxlength', 'replaceintitle', 'columns', 'rows', 'rowsize', 'rowcolformat', 'resultsheader', 'resultsfooter', 'oneresultheader', 'oneresultfooter', 'noresultsheader', 'suppresserrors', 'noresultsfooter', 'format', 'groupMultiTemplateResults' } for _, k in ipairs( toRemove ) do query[k] = nil end end local function formatInclude( query ) checkTypeForNamedArg( 'Module:DPLlua.ask', 'include', query, 'string' ) query = split( query, ',', true ) local includedParamNames = {} local sectionAttributes = {} for i = 1, #query do if query[i]:match( '%b{}' ) then -- Check if we are including a template local templateName, extra = query[i]:match( '{(.-)[¦|}](.*)' ) if hasContent( extra ) then local phantomTemplateName = extra:match( '^(.-)}' ) or extra:match( '^[./].+' ) local phantomTemplatePrefix = extra:match( '^(.-)}' ) and '' or templateName local params = extra:gsub( '^.-}', '' ):gsub( '^[./].+', '' ):gsub( ':%-', '' ) local sur = hasContent( phantomTemplateName ) and ('¦' .. phantomTemplatePrefix .. phantomTemplateName) or '' query[i] = string.format( '{%s%s}%s', templateName, sur, params ) if hasContent( phantomTemplateName ) then table.insert( includedParamNames, { name=phantomTemplatePrefix..phantomTemplateName, isTemplate=true, hasPhantomTemplate=true } ) table.insert( sectionAttributes, { hasPhantomTemplate=true } ) else for param in params:gmatch( ':([^:]*)' ) do param = trim( param ) table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } ) end table.insert( sectionAttributes, { hasPhantomTemplate=false } ) end else query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } ) table.insert( sectionAttributes, { hasPhantomTemplate=false } ) end else table.insert( includedParamNames, { name=trim( query[i] ) } ) table.insert( sectionAttributes, { hasPhantomTemplate=false } ) end end return table.concat( query, ',' ), includedParamNames, sectionAttributes end local function formatDpl( query ) local queries = {} local count = query.count or 500 local offset = query.offset or 0 local usesInclude = false local includedParamNames = {} local sectionAttributes query.count = nil query.offset = nil -- Use table format so we can place dataContentMarkers around each included parameter. The secseparator -- is needed to add dataContentMarkers when a phantom template is used local dplStringInclude = [=[ {{#dpl: |noresultsheader=@@ |count=%s |offset=%s |%s |table=, |listseparators=,\n¦-\n¦[[%%PAGE%%¦]],, |tablerow=%s |secseparators=%s }}]=] -- Table format requires an include statement so we use format instead. -- This is also a lot faster than adding an empty include statement local dplStringNoInclude = [=[ {{#dpl: |noresultsheader=@@ |count=%s |offset=%s |%s |format=,¦-¦[[%%PAGE%%¦]],, }}]=] -- Auto generate more than one dpl if count > 500 -- The results of these are later combined for i = 1, math.ceil( count / 500 ) do local params = {} for k, v in pairs( query ) do if k == 'include' then v, includedParamNames, sectionAttributes = formatInclude( v ) usesInclude = true end if type( v ) == 'table' then for _, x in ipairs( v ) do table.insert( params, k .. '=' .. tostring( x ):gsub( '|', '¦' ) ) end else table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) ) end end if usesInclude then local secseparators = '' for _, v in ipairs( sectionAttributes ) do if v.hasPhantomTemplate then -- Phantom templates need this because they ignore tablerow formatting secseparators = secseparators .. '¶¦' .. dataContentMarker .. ',' .. dataContentMarker .. ',' else secseparators = secseparators .. '¶¦,,' end end table.insert( queries, string.format( dplStringInclude, count > 500 and 500 or count, offset, table.concat( params, '\n|' ), string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ), secseparators ) ) else table.insert( queries, string.format( dplStringNoInclude, count > 500 and 500 or count, offset, table.concat( params, '\n|' ) ) ) end count = count - 500 offset = offset + 500 end table.insert( allIncludedParamNames, includedParamNames ) return table.concat( queries ) end local function toTable( query, groupMultiTemplateResults ) local includedParamNames = table.remove( allIncludedParamNames, 1 ) local usesInclude = #includedParamNames > 0 local res = {} query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end ) if query:find( '^@@' ) then -- @@ is used when no result is found return res end if usesInclude then query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape ) end query = trim( query ) query = split( query, '|-', true ) -- Results of the returned pages are separated by |- for _, v in ipairs( query ) do if hasContent( v ) and not v:find( '^@@' ) then v = trim( v ) local title = v:match( '^|%[%[(.-)|' ) local rawDataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title if not usesInclude then if title and title ~= '' then table.insert( res, title ) end else -- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) their results are separated by a pipe rawDataList = split( rawDataList, '|', true ) local cleanedDataList = {} for _incIndex, dataItem in ipairs( rawDataList ) do local incIndex = ((_incIndex - 1) % #includedParamNames) + 1 -- Needed in case the same template appears multiple times on the same page dataItem = unEscape( dataItem ) dataItem = trim( dataItem ) if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template -- When we include an entire template we use the %ARGS% parameter supplied by dpl. -- However all | characters are repaced with §, e.g.: -- §namelessParam -- §param = text [[wowee§link text]] -- §param2 = text {{something§something else}} dataItem = dataItem:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end ) dataItem = mw.text.unstripNoWiki( dataItem ) -- Unstrip nowiki so we can clean their content dataItem = fixCurlyBrackets( dataItem ) -- When using the %ARGS% dpl parameter, curly brackets are replaced with ❴ (U+2774) and ❵ (U+2775) dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end ) dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki local _dataItem = {} if dataItem ~= '' then dataItem = split( dataItem:sub( 3 ), '§' ) -- The sub(3) removes the first § at the start. § is 2 bytes wide so start at index 3 for i, item in ipairs( dataItem ) do if item:find( '=' ) then -- Check if the parameter is named or unnamed local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' ) _dataItem[ param ] = value else table.insert( _dataItem, trim( item ) ) end end end dataItem = _dataItem end local dataListIndex = groupMultiTemplateResults and 1 or math.ceil( _incIndex / #includedParamNames ) if includedParamNames[ incIndex ].isTemplate and not includedParamNames[ incIndex ].includeAll and not includedParamNames[ incIndex ].hasPhantomTemplate then -- This means there was an include in the form 'include = {template}:param' local templateName = includedParamNames[ incIndex ].name local paramName = includedParamNames[ incIndex ].param paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {} cleanedDataList[ dataListIndex ][ templateName ] = cleanedDataList[ dataListIndex ][ templateName ] or {} if groupMultiTemplateResults and _incIndex > #includedParamNames then mergeItem( cleanedDataList[ dataListIndex ][ templateName ], paramName, dataItem ) else cleanedDataList[ dataListIndex ][ templateName ][ paramName ] = dataItem end else local templateName = includedParamNames[ incIndex ].name cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {} if groupMultiTemplateResults and _incIndex > #includedParamNames then mergeItem( cleanedDataList[ dataListIndex ], templateName, dataItem ) else cleanedDataList[ dataListIndex ][ templateName ] = dataItem end end end if title and title ~= '' then for _, v in ipairs( cleanedDataList ) do table.insert( res, { title=title, include=v } ) end end end end end return res end -- Accepts a series of tables each containig the settings for a dpl query. -- Combinig multiple dpl queries yields better performance than doing them sequentially function dpl.ask( ... ) local formatTime = os.clock() local queries = { ... } local wantsGrouping = {} for i = 1, #queries do checkType( 'Module:DPLlua.ask', i, queries[i], 'table' ) table.insert( wantsGrouping, queries[i].groupMultiTemplateResults or false ) removeFormattingSettings( queries[i] ) queries[i] = formatDpl( queries[i] ) end formatTime = os.clock() - formatTime local DPLtime = os.clock() queries = table.concat( queries, '$@µ@$' ) queries = mw.getCurrentFrame():preprocess( queries ) queries = split( queries, '$@µ@$', true ) DPLtime = os.clock() - DPLtime for i = 1, #queries do local parseTime = os.clock() queries[i] = toTable( queries[i], wantsGrouping[i] ) parseTime = os.clock() - parseTime queries[i]['DPL time'] = DPLtime queries[i]['Parse time'] = math.floor( (formatTime + parseTime) * 1e5 ) / 1e5 -- os.clock() has a resolution of 10µs end return unpack( queries ) end -- function dpl.test() -- local time = os.clock() -- local a, b = dpl.ask({ -- namespace = 'Module', -- linksto = 'Module:Chart data', -- distinct = 'strict', -- ordermethod = 'title', -- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data', -- ignorecase = 'true', -- allowcachedresults = false -- },{ -- namespace = 'Module', -- linksto = 'Module:Enum', -- distinct = 'strict', -- ordermethod = 'title', -- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Enum', -- ignorecase = 'true', -- allowcachedresults = false -- }) -- mw.logObject(a) -- mw.logObject(b) -- local a, b = dpl.ask({ -- namespace = 'Module', -- linksto = 'Module:Chart data', -- distinct = 'strict', -- ordermethod = 'title', -- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data', -- ignorecase = 'true', -- allowcachedresults = false -- },{ -- namespace = '', -- ignorecase = 'true', -- uses = 'Template:Infobox Recipe', -- count = 50, -- include = '{Infobox Recipe},{Infobox Item}', -- allowcachedresults = false -- }) -- mw.logObject(a) -- mw.logObject(b) -- local a = dpl.ask{ -- namespace = '', -- uses = 'Template:Infobox Recipe', -- include = '{Infobox Recipe}:skill:name,{Infobox Item}:update,{Infobox Item|test}', -- count = 50, -- ordermethod = 'title', -- } -- mw.logObject(a) -- local q = dpl.ask{ -- uses = "Template:Collections table", -- category = "Archaeology collections", -- -- include = "{Infobox collection}:reward,{Collections table}:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15", -- include = "{Infobox collection}:reward,{Collections table}", -- count = 100 -- } -- mw.logObject(q) -- local q = dpl.ask{ -- namespace = "", -- uses = "Template:Infobox spell", -- notcategory = {"Removed content", "Removed spells"}, -- nottitlematch = {"Enchant Crossbow Bolt", "Storm of Armadyl"}, -- include = "{Infobox spell}", -- } -- mw.logObject(q) -- local list = dpl.ask{ -- namespace = 'Template', -- uses = 'Template:Navbox', -- ordermethod = 'title', -- include = '{Navbox}:gtitle1:gtitle2', -- count = 1, -- offset = 3 -- } -- mw.logObject(list) -- local list = dpl.ask{ -- namespace = 'User', -- titlematch = 'CephHunter/Sandbox/test1', -- include = '{User:CephHunter/Sandbox/test2|User:CephHunter/Sandbox/test3},{User:CephHunter/Sandbox/test3}:1', -- } -- mw.logObject(list) -- mw.logObject(dpl.ask{ -- namespace = 'User', -- ignorecase = 'true', -- titlematch = 'CephHunter/Sandbox/test1', -- include = '{User:CephHunter/Sandbox/test2}' -- }) -- mw.logObject(dpl.ask{ -- namespace = 'Module', -- uses = 'Template:Helper module', -- titlematch = '%/doc', -- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%', -- ordermethod = 'title', -- include = '{Helper module}, {Helper module}:example', -- count = 1, -- offset = 13 -- }) -- mw.logObject(dpl.ask{ -- namespace = 'Module', -- titlematch = 'Chart data|Absorbative calculator', -- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%|%/doc|DPLlua%', -- ordermethod = 'title', -- include = '%0' -- }) -- mw.logObject(dpl.ask{ -- uses = 'Template:Collections table', -- include = '{Collections table}', -- count = 5 -- }) -- mw.log(os.clock()-time) -- end return dpl -- </nowiki> a4585a9ed619b57adfaa5cf8d9279da529e74df5 Category:Templates using TemplateStyles 14 34 66 2021-05-09T07:08:56Z Star>Alistair3149 0 wikitext text/x-wiki {{Category header|templates|using [[Star Citizen:TemplateStyles|TemplateStyles]]}} [[Category:Templates]] 7281aa1e395de9d8c368a3975548ace744177ec3 Category:Graph, chart, and plot templates 14 13 24 2021-05-21T12:05:38Z Star>Facerafter 0 1 revision imported wikitext text/x-wiki {{Category header|templates|used to produce graphs}} [[Category:Templates]] d2eb48d7551d51c120fdbfa06a3981e0053afb31 Category:Main page templates 14 21 40 2021-05-21T12:05:38Z Star>Facerafter 0 1 revision imported wikitext text/x-wiki {{Category header|templates|used on the main page}} [[Category:Templates]] fe5a1f6fb0db7ec3bd95014a7935715fb7558c94 Category:Navplates 14 25 48 2021-05-21T20:58:04Z Star>Facerafter 0 wikitext text/x-wiki '''Navplates''' are navigation components that help visitor to visit pages that fall under the same category. [[Category:Templates]] ffa7595179dc81205203c976231a54a062e09851 Category:External link templates 14 9 16 2022-05-04T18:29:23Z Star>Alistair3149 0 Created page with "[[Category:Templates]]" wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Template:Category header 10 46 90 2022-05-10T07:07:39Z Star>Alistair3149 0 Wrap in note template wikitext text/x-wiki <includeonly>{{Note|This category contains {{{1}}}{{#if:{{{2|}}}|{{#ifeq:{{lc:{{{related|}}}}}|no||{{nbsp}}related to}}{{nbsp}}{{{2}}}}}. {{#if:{{{3|}}}|This category is automatically added by {{{4|}}}.}}}}</includeonly><noinclude>{{/doc}}</noinclude> a396b20e4e0c621cc7538e9a0f085cfbbd37a811 Template:Day 10 2 2 2022-10-13T21:23:08Z Star>Alistair3149 0 Short description already set in day header wikitext text/x-wiki <includeonly>'''{{{1|{{FULLPAGENAME}}}}}''' is the {{#switch:{{#time:z|{{{1|{{PAGENAME}}}}}}} |0=first |1=second |2=third |3=fourth |4=fifth |5=sixth |6=seventh |7=eighth |8=ninth |{{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}+1}}}} }} day of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3 | |&#32;({{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}+1}}}} in leap years) }} in the Gregorian calendar.{{#switch:{{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}} |0= |1=&#32;One day remains until the end of the year. |2=&#32;Two days remain until the end of the year. |3=&#32;Three days remain until the end of the year. |4=&#32;Four days remain until the end of the year. |5=&#32;Five days remain until the end of the year. |6=&#32;Six days remain until the end of the year. |7=&#32;Seven days remain until the end of the year. |8=&#32;Eight days remain until the end of the year. |9=&#32;Nine days remain until the end of the year. |&#32; {{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}} days remain until the end of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3 |&#32;({{#expr:365-{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}}} in leap years) | }}. }}</includeonly><noinclude>{{/doc}}</noinclude> 530dc54fd9473a69e2d1ff775d7d2b2a6c206768 Module:Hatnote list 828 50 98 2023-01-23T23:06:33Z star>Alistair3149 0 Scribunto text/plain -------------------------------------------------------------------------------- -- Module:Hatnote list -- -- -- -- This module produces and formats lists for use in hatnotes. In particular, -- -- it implements the for-see list, i.e. lists of "For X, see Y" statements, -- -- as used in {{about}}, {{redirect}}, and their variants. Also introduced -- -- are andList & orList helpers for formatting lists with those conjunctions. -- -------------------------------------------------------------------------------- local mArguments --initialize lazily local mFormatLink = require('Module:Format link') local mHatnote = require('Module:Hatnote') local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local p = {} -------------------------------------------------------------------------------- -- List stringification helper functions -- -- These functions are used for stringifying lists, usually page lists inside -- the "Y" portion of "For X, see Y" for-see items. -------------------------------------------------------------------------------- --default options table used across the list stringification functions local stringifyListDefaultOptions = { conjunction = "and", separator = ",", altSeparator = ";", space = " ", formatted = false } --Searches display text only local function searchDisp(haystack, needle) return string.find( string.sub(haystack, (string.find(haystack, '|') or 0) + 1), needle ) end -- Stringifies a list generically; probably shouldn't be used directly local function stringifyList(list, options) -- Type-checks, defaults, and a shortcut checkType("stringifyList", 1, list, "table") if #list == 0 then return nil end checkType("stringifyList", 2, options, "table", true) options = options or {} for k, v in pairs(stringifyListDefaultOptions) do if options[k] == nil then options[k] = v end end local s = options.space -- Format the list if requested if options.formatted then list = mFormatLink.formatPages( {categorizeMissing = mHatnote.missingTargetCat}, list ) end -- Set the separator; if any item contains it, use the alternate separator local separator = options.separator for k, v in pairs(list) do if searchDisp(v, separator) then separator = options.altSeparator break end end -- Set the conjunction, apply Oxford comma, and force a comma if #1 has "§" local conjunction = s .. options.conjunction .. s if #list == 2 and searchDisp(list[1], "§") or #list > 2 then conjunction = separator .. conjunction end -- Return the formatted string return mw.text.listToText(list, separator .. s, conjunction) end --DRY function function p.conjList (conj, list, fmt) return stringifyList(list, {conjunction = conj, formatted = fmt}) end -- Stringifies lists with "and" or "or" function p.andList (...) return p.conjList("and", ...) end function p.orList (...) return p.conjList("or", ...) end -------------------------------------------------------------------------------- -- For see -- -- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the -- {{about}} and {{redirect}} templates and their variants. -------------------------------------------------------------------------------- --default options table used across the forSee family of functions local forSeeDefaultOptions = { andKeyword = 'and', title = mw.title.getCurrentTitle().text, otherText = 'other uses', forSeeForm = 'For %s, see %s.', } --Collapses duplicate punctuation local function punctuationCollapse (text) local replacements = { ["%.%.$"] = ".", ["%?%.$"] = "?", ["%!%.$"] = "!", ["%.%]%]%.$"] = ".]]", ["%?%]%]%.$"] = "?]]", ["%!%]%]%.$"] = "!]]" } for k, v in pairs(replacements) do text = string.gsub(text, k, v) end return text end -- Structures arguments into a table for stringification, & options function p.forSeeArgsToTable (args, from, options) -- Type-checks and defaults checkType("forSeeArgsToTable", 1, args, 'table') checkType("forSeeArgsToTable", 2, from, 'number', true) from = from or 1 checkType("forSeeArgsToTable", 3, options, 'table', true) options = options or {} for k, v in pairs(forSeeDefaultOptions) do if options[k] == nil then options[k] = v end end -- maxArg's gotten manually because getArgs() and table.maxn aren't friends local maxArg = 0 for k, v in pairs(args) do if type(k) == 'number' and k > maxArg then maxArg = k end end -- Structure the data out from the parameter list: -- * forTable is the wrapper table, with forRow rows -- * Rows are tables of a "use" string & a "pages" table of pagename strings -- * Blanks are left empty for defaulting elsewhere, but can terminate list local forTable = {} local i = from local terminated = false -- If there is extra text, and no arguments are given, give nil value -- to not produce default of "For other uses, see foo (disambiguation)" if options.extratext and i > maxArg then return nil end -- Loop to generate rows repeat -- New empty row local forRow = {} -- On blank use, assume list's ended & break at end of this loop forRow.use = args[i] if not args[i] then terminated = true end -- New empty list of pages forRow.pages = {} -- Insert first pages item if present table.insert(forRow.pages, args[i + 1]) -- If the param after next is "and", do inner loop to collect params -- until the "and"'s stop. Blanks are ignored: "1|and||and|3" → {1, 3} while args[i + 2] == options.andKeyword do if args[i + 3] then table.insert(forRow.pages, args[i + 3]) end -- Increment to next "and" i = i + 2 end -- Increment to next use i = i + 2 -- Append the row table.insert(forTable, forRow) until terminated or i > maxArg return forTable end -- Stringifies a table as formatted by forSeeArgsToTable function p.forSeeTableToString (forSeeTable, options) -- Type-checks and defaults checkType("forSeeTableToString", 1, forSeeTable, "table", true) checkType("forSeeTableToString", 2, options, "table", true) options = options or {} for k, v in pairs(forSeeDefaultOptions) do if options[k] == nil then options[k] = v end end -- Stringify each for-see item into a list local strList = {} if forSeeTable then for k, v in pairs(forSeeTable) do local useStr = v.use or options.otherText local pagesStr = p.andList(v.pages, true) or mFormatLink._formatLink{ categorizeMissing = mHatnote.missingTargetCat, link = mHatnote.disambiguate(options.title) } local forSeeStr = string.format(options.forSeeForm, useStr, pagesStr) forSeeStr = punctuationCollapse(forSeeStr) table.insert(strList, forSeeStr) end end if options.extratext then table.insert(strList, punctuationCollapse(options.extratext..'.')) end -- Return the concatenated list return table.concat(strList, ' ') end -- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps -- but not blank/whitespace values. Ignores named args and args < "from". function p._forSee (args, from, options) local forSeeTable = p.forSeeArgsToTable(args, from, options) return p.forSeeTableToString(forSeeTable, options) end -- As _forSee, but uses the frame. function p.forSee (frame, from, options) mArguments = require('Module:Arguments') return p._forSee(mArguments.getArgs(frame), from, options) end return p d0828422b1aa0d0d0092d699d059c9e882260398 Module:Hatnote/styles.css 828 47 92 2023-01-24T01:51:43Z Star>Alistair3149 0 text text/plain .hatnote-container { display: flex; align-items: center; padding: var( --space-sm ) var( --space-md ); margin-top: var( --space-xs ); margin-bottom: var( --space-md ); background: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); color: var( --color-base--subtle ); font-size: 0.875rem; line-height: var( --line-height-xs ); } .hatnote-icon img { width: 14px; height: auto; margin-right: var( --space-xs ); opacity: var( --opacity-icon-base ); } /* Dark theme */ html.skin-citizen-dark .hatnote-icon img { filter: invert( 1 ); } 44850b74680c356f2514e4292d2130fb67f3b46d Module:Arguments 828 40 78 2023-01-24T03:54:04Z Star>Alistair3149 0 Protected "[[Module:Arguments]]" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) Scribunto text/plain -- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly. local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local arguments = {} -- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it. local function tidyValDefault(key, val) if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val == '' then return nil else return val end else return val end end local function tidyValTrimOnly(key, val) if type(val) == 'string' then return val:match('^%s*(.-)%s*$') else return val end end local function tidyValRemoveBlanksOnly(key, val) if type(val) == 'string' then if val:find('%S') then return val else return nil end else return val end end local function tidyValNoChange(key, val) return val end local function matchesTitle(given, title) local tp = type( given ) return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title end local translate_mt = { __index = function(t, k) return k end } function arguments.getArgs(frame, options) checkType('getArgs', 1, frame, 'table', true) checkType('getArgs', 2, options, 'table', true) frame = frame or {} options = options or {} --[[ -- Set up argument translation. --]] options.translate = options.translate or {} if getmetatable(options.translate) == nil then setmetatable(options.translate, translate_mt) end if options.backtranslate == nil then options.backtranslate = {} for k,v in pairs(options.translate) do options.backtranslate[v] = k end end if options.backtranslate and getmetatable(options.backtranslate) == nil then setmetatable(options.backtranslate, { __index = function(t, k) if options.translate[k] ~= k then return nil else return k end end }) end --[[ -- Get the argument tables. If we were passed a valid frame object, get the -- frame arguments (fargs) and the parent frame arguments (pargs), depending -- on the options set and on the parent frame's availability. If we weren't -- passed a valid frame object, we are being called from another Lua module -- or from the debug console, so assume that we were passed a table of args -- directly, and assign it to a new variable (luaArgs). --]] local fargs, pargs, luaArgs if type(frame.args) == 'table' and type(frame.getParent) == 'function' then if options.wrappers then --[[ -- The wrappers option makes Module:Arguments look up arguments in -- either the frame argument table or the parent argument table, but -- not both. This means that users can use either the #invoke syntax -- or a wrapper template without the loss of performance associated -- with looking arguments up in both the frame and the parent frame. -- Module:Arguments will look up arguments in the parent frame -- if it finds the parent frame's title in options.wrapper; -- otherwise it will look up arguments in the frame object passed -- to getArgs. --]] local parent = frame:getParent() if not parent then fargs = frame.args else local title = parent:getTitle():gsub('/sandbox$', '') local found = false if matchesTitle(options.wrappers, title) then found = true elseif type(options.wrappers) == 'table' then for _,v in pairs(options.wrappers) do if matchesTitle(v, title) then found = true break end end end -- We test for false specifically here so that nil (the default) acts like true. if found or options.frameOnly == false then pargs = parent.args end if not found or options.parentOnly == false then fargs = frame.args end end else -- options.wrapper isn't set, so check the other options. if not options.parentOnly then fargs = frame.args end if not options.frameOnly then local parent = frame:getParent() pargs = parent and parent.args or nil end end if options.parentFirst then fargs, pargs = pargs, fargs end else luaArgs = frame end -- Set the order of precedence of the argument tables. If the variables are -- nil, nothing will be added to the table, which is how we avoid clashes -- between the frame/parent args and the Lua args. local argTables = {fargs} argTables[#argTables + 1] = pargs argTables[#argTables + 1] = luaArgs --[[ -- Generate the tidyVal function. If it has been specified by the user, we -- use that; if not, we choose one of four functions depending on the -- options chosen. This is so that we don't have to call the options table -- every time the function is called. --]] local tidyVal = options.valueFunc if tidyVal then if type(tidyVal) ~= 'function' then error( "bad value assigned to option 'valueFunc'" .. '(function expected, got ' .. type(tidyVal) .. ')', 2 ) end elseif options.trim ~= false then if options.removeBlanks ~= false then tidyVal = tidyValDefault else tidyVal = tidyValTrimOnly end else if options.removeBlanks ~= false then tidyVal = tidyValRemoveBlanksOnly else tidyVal = tidyValNoChange end end --[[ -- Set up the args, metaArgs and nilArgs tables. args will be the one -- accessed from functions, and metaArgs will hold the actual arguments. Nil -- arguments are memoized in nilArgs, and the metatable connects all of them -- together. --]] local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} setmetatable(args, metatable) local function mergeArgs(tables) --[[ -- Accepts multiple tables as input and merges their keys and values -- into one table. If a value is already present it is not overwritten; -- tables listed earlier have precedence. We are also memoizing nil -- values, which can be overwritten if they are 's' (soft). --]] for _, t in ipairs(tables) do for key, val in pairs(t) do if metaArgs[key] == nil and nilArgs[key] ~= 'h' then local tidiedVal = tidyVal(key, val) if tidiedVal == nil then nilArgs[key] = 's' else metaArgs[key] = tidiedVal end end end end end --[[ -- Define metatable behaviour. Arguments are memoized in the metaArgs table, -- and are only fetched from the argument tables once. Fetching arguments -- from the argument tables is the most resource-intensive step in this -- module, so we try and avoid it where possible. For this reason, nil -- arguments are also memoized, in the nilArgs table. Also, we keep a record -- in the metatable of when pairs and ipairs have been called, so we do not -- run pairs and ipairs on the argument tables more than once. We also do -- not run ipairs on fargs and pargs if pairs has already been run, as all -- the arguments will already have been copied over. --]] metatable.__index = function (t, key) --[[ -- Fetches an argument when the args table is indexed. First we check -- to see if the value is memoized, and if not we try and fetch it from -- the argument tables. When we check memoization, we need to check -- metaArgs before nilArgs, as both can be non-nil at the same time. -- If the argument is not present in metaArgs, we also check whether -- pairs has been run yet. If pairs has already been run, we return nil. -- This is because all the arguments will have already been copied into -- metaArgs by the mergeArgs function, meaning that any other arguments -- must be nil. --]] if type(key) == 'string' then key = options.translate[key] end local val = metaArgs[key] if val ~= nil then return val elseif metatable.donePairs or nilArgs[key] then return nil end for _, argTable in ipairs(argTables) do local argTableVal = tidyVal(key, argTable[key]) if argTableVal ~= nil then metaArgs[key] = argTableVal return argTableVal end end nilArgs[key] = 'h' return nil end metatable.__newindex = function (t, key, val) -- This function is called when a module tries to add a new value to the -- args table, or tries to change an existing value. if type(key) == 'string' then key = options.translate[key] end if options.readOnly then error( 'could not write to argument table key "' .. tostring(key) .. '"; the table is read-only', 2 ) elseif options.noOverwrite and args[key] ~= nil then error( 'could not write to argument table key "' .. tostring(key) .. '"; overwriting existing arguments is not permitted', 2 ) elseif val == nil then --[[ -- If the argument is to be overwritten with nil, we need to erase -- the value in metaArgs, so that __index, __pairs and __ipairs do -- not use a previous existing value, if present; and we also need -- to memoize the nil in nilArgs, so that the value isn't looked -- up in the argument tables if it is accessed again. --]] metaArgs[key] = nil nilArgs[key] = 'h' else metaArgs[key] = val end end local function translatenext(invariant) local k, v = next(invariant.t, invariant.k) invariant.k = k if k == nil then return nil elseif type(k) ~= 'string' or not options.backtranslate then return k, v else local backtranslate = options.backtranslate[k] if backtranslate == nil then -- Skip this one. This is a tail call, so this won't cause stack overflow return translatenext(invariant) else return backtranslate, v end end end metatable.__pairs = function () -- Called when pairs is run on the args table. if not metatable.donePairs then mergeArgs(argTables) metatable.donePairs = true end return translatenext, { t = metaArgs } end local function inext(t, i) -- This uses our __index metamethod local v = t[i + 1] if v ~= nil then return i + 1, v end end metatable.__ipairs = function (t) -- Called when ipairs is run on the args table. return inext, t, 0 end return args end return arguments 3134ecce8429b810d445e29eae115e2ae4c36c53 Template:Note 10 42 82 2023-01-24T21:45:35Z Star>Alistair3149 0 Alistair3149 moved page [[Template:Note]] to [[Template:Hatnote]] wikitext text/x-wiki #REDIRECT [[Template:Hatnote]] 9582e82fbead373024765d896e4930eee521d846 Template:Hatnote 10 48 94 2023-01-24T21:45:35Z Star>Alistair3149 0 Alistair3149 moved page [[Template:Note]] to [[Template:Hatnote]] wikitext text/x-wiki <includeonly>{{#invoke:Hatnote|hatnote}}</includeonly><noinclude>{{/doc}}</noinclude> d9029e1bc2de056708cda99e6ce883644c1661e4 Category:Preload text templates 14 28 54 2023-04-25T16:46:32Z Star>Alistair3149 0 Created page with "{{Category header|templates|used for article creation}} [[Category:Templates]]" wikitext text/x-wiki {{Category header|templates|used for article creation}} [[Category:Templates]] 21360b4c5b0d6bef10209484084e8beb67641662 Module:Infobox 828 58 114 2023-05-29T18:00:43Z star>Alistair3149 0 Load templatestyles through module instead Scribunto text/plain -- -- This module implements {{Infobox}} -- local p = {} -- local navbar = require('Module:Navbar')._navbar local args = {} local origArgs local root local function notempty( s ) return s and s:match( '%S' ) end local function fixChildBoxes(sval, tt) if notempty(sval) then local marker = '<span class=special_infobox_marker>' local s = sval s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1') s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker) if s:match(marker) then s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '') s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1') s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1') s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1') s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1') s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1') s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1') s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1') s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1') end if s:match(marker) then local subcells = mw.text.split(s, marker) s = '' for k = 1, #subcells do if k == 1 then s = s .. subcells[k] .. '</' .. tt .. '></tr>' elseif k == #subcells then local rowstyle = ' style="display:none"' if notempty(subcells[k]) then rowstyle = '' end s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' .. subcells[k] elseif notempty(subcells[k]) then if (k % 2) == 0 then s = s .. subcells[k] else s = s .. '<tr><' .. tt .. ' colspan=2>\n' .. subcells[k] .. '</' .. tt .. '></tr>' end end end end -- the next two lines add a newline at the end of lists for the PHP parser -- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=849054481 -- remove when [[:phab:T191516]] is fixed or OBE s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n') s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n') s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1') s = mw.ustring.gsub(s, '^(%{%|)', '\n%1') return s else return sval end end local function union(t1, t2) -- Returns the union of the values of two tables, as a sequence. local vals = {} for k, v in pairs(t1) do vals[v] = true end for k, v in pairs(t2) do vals[v] = true end local ret = {} for k, v in pairs(vals) do table.insert(ret, k) end return ret end local function getArgNums(prefix) -- Returns a table containing the numbers of the arguments that exist -- for the specified prefix. For example, if the prefix was 'data', and -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}. local nums = {} for k, v in pairs(args) do local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$') if num then table.insert(nums, tonumber(num)) end end table.sort(nums) return nums end local function addRow(rowArgs) -- Adds a row to the infobox, with either a header cell -- or a label/data cell combination. if rowArgs.header then root :tag('tr') :addClass(rowArgs.rowclass) :cssText(rowArgs.rowstyle) :attr('id', rowArgs.rowid) :tag('th') :attr('colspan', 2) :attr('id', rowArgs.headerid) :addClass(rowArgs.class) :addClass(args.headerclass) ----:css('text-align', 'center') :cssText(args.headerstyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.header, 'th')) elseif rowArgs.data then local row = root:tag('tr') row:addClass(rowArgs.rowclass) row:cssText(rowArgs.rowstyle) row:attr('id', rowArgs.rowid) if rowArgs.label then row :tag('th') :attr('scope', 'row') :attr('id', rowArgs.labelid) :cssText(args.labelstyle) :cssText(rowArgs.rowcellstyle) :wikitext(rowArgs.label) :done() end local dataCell = row:tag('td') if not rowArgs.label then dataCell :attr('colspan', 2) ----:css('text-align', 'center') end dataCell :attr('id', rowArgs.dataid) :addClass(rowArgs.class) :cssText(rowArgs.datastyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.data, 'td')) end end local function renderTitle() if not args.title then return end root :tag('caption') :addClass(args.titleclass) :cssText(args.titlestyle) :wikitext(args.title) end local function renderAboveRow() if not args.above then return end root :tag('tr') :tag('th') :attr('colspan', 2) :addClass(args.aboveclass) --:css('text-align', 'center') --:css('font-size', '125%') --:css('font-weight', 'bold') :cssText(args.abovestyle) :wikitext(fixChildBoxes(args.above,'th')) end local function renderBelowRow() if not args.below then return end root :tag('tr') :tag('td') :attr('colspan', '2') :addClass(args.belowclass) --:css('text-align', 'center') :cssText(args.belowstyle) :wikitext(fixChildBoxes(args.below,'td')) end local function renderSubheaders() if args.subheader then args.subheader1 = args.subheader end if args.subheaderrowclass then args.subheaderrowclass1 = args.subheaderrowclass end local subheadernums = getArgNums('subheader') for k, num in ipairs(subheadernums) do addRow({ data = args['subheader' .. tostring(num)], datastyle = args.subheaderstyle, rowcellstyle = args['subheaderstyle' .. tostring(num)], class = args.subheaderclass, rowclass = args['subheaderrowclass' .. tostring(num)] }) end end local function renderImages() if args.image then args.image1 = args.image end if args.caption then args.caption1 = args.caption end local imagenums = getArgNums('image') for k, num in ipairs(imagenums) do local caption = args['caption' .. tostring(num)] local data = mw.html.create():wikitext(args['image' .. tostring(num)]) if caption then data :tag('div') :cssText(args.captionstyle) :wikitext(caption) end addRow({ data = tostring(data), datastyle = args.imagestyle, class = args.imageclass, rowclass = args['imagerowclass' .. tostring(num)] }) end end local function renderRows() -- Gets the union of the header and data argument numbers, -- and renders them all in order using addRow. local rownums = union(getArgNums('header'), getArgNums('data')) table.sort(rownums) for k, num in ipairs(rownums) do addRow({ header = args['header' .. tostring(num)], label = args['label' .. tostring(num)], data = args['data' .. tostring(num)], datastyle = args.datastyle, class = args['class' .. tostring(num)], rowclass = args['rowclass' .. tostring(num)], rowstyle = args['rowstyle' .. tostring(num)], rowcellstyle = args['rowcellstyle' .. tostring(num)], dataid = args['dataid' .. tostring(num)], labelid = args['labelid' .. tostring(num)], headerid = args['headerid' .. tostring(num)], rowid = args['rowid' .. tostring(num)] }) end end --local function renderNavBar() -- if not args.name then return end -- -- root -- :tag('tr') -- :tag('td') -- :attr('colspan', '2') -- --:css('text-align', 'right') -- :wikitext(navbar{ -- args.name, -- mini = 1, -- }) --end local function renderItalicTitle() local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title']) if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'})) end end local function renderTrackingCategories() if args.decat ~= 'yes' then if args.child == 'yes' then if args.title then root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]') end elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then root:wikitext('[[Category:Articles which use infobox templates with no data rows]]') end end end local function _infobox() -- Specify the overall layout of the infobox, with special settings -- if the infobox is used as a 'child' inside another infobox. if args.child ~= 'yes' then root = mw.html.create('table') root :addClass((args.subbox ~= 'yes') and 'infobox' or nil) :addClass(args.bodyclass) --if args.subbox == 'yes' then --root --:css('padding', '0') --:css('border', 'none') --:css('margin', '-3px') --:css('width', 'auto') --:css('min-width', '100%') --:css('font-size', '100%') --:css('clear', 'none') --:css('float', 'none') --:css('background-color', 'transparent') --else --root --:css('width', '400px') -- Changed from 22em --end root :cssText(args.bodystyle) renderTitle() renderAboveRow() else root = mw.html.create() root :wikitext(args.title) end renderSubheaders() renderImages() renderRows() renderBelowRow() --renderNavBar() renderItalicTitle() renderTrackingCategories() return tostring(root) .. mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Infobox/styles.css' } } end local function preprocessSingleArg(argName) -- If the argument exists and isn't blank, add it to the argument table. -- Blank arguments are treated as nil to match the behaviour of ParserFunctions. if origArgs[argName] and origArgs[argName] ~= '' then args[argName] = origArgs[argName] end end local function preprocessArgs(prefixTable, step) -- Assign the parameters with the given prefixes to the args table, in order, in batches -- of the step size specified. This is to prevent references etc. from appearing in the -- wrong order. The prefixTable should be an array containing tables, each of which has -- two possible fields, a "prefix" string and a "depend" table. The function always parses -- parameters containing the "prefix" string, but only parses parameters in the "depend" -- table if the prefix parameter is present and non-blank. if type(prefixTable) ~= 'table' then error("Non-table value detected for the prefix table", 2) end if type(step) ~= 'number' then error("Invalid step value detected", 2) end -- Get arguments without a number suffix, and check for bad input. for i,v in ipairs(prefixTable) do if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then error('Invalid input detected to preprocessArgs prefix table', 2) end preprocessSingleArg(v.prefix) -- Only parse the depend parameter if the prefix parameter is present and not blank. if args[v.prefix] and v.depend then for j, dependValue in ipairs(v.depend) do if type(dependValue) ~= 'string' then error('Invalid "depend" parameter value detected in preprocessArgs') end preprocessSingleArg(dependValue) end end end -- Get arguments with number suffixes. local a = 1 -- Counter variable. local moreArgumentsExist = true while moreArgumentsExist == true do moreArgumentsExist = false for i = a, a + step - 1 do for j,v in ipairs(prefixTable) do local prefixArgName = v.prefix .. tostring(i) if origArgs[prefixArgName] then moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones. preprocessSingleArg(prefixArgName) end -- Process the depend table if the prefix argument is present and not blank, or -- we are processing "prefix1" and "prefix" is present and not blank, and -- if the depend table is present. if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then for j,dependValue in ipairs(v.depend) do local dependArgName = dependValue .. tostring(i) preprocessSingleArg(dependArgName) end end end end a = a + step end end function p.infobox(frame) -- If called via #invoke, use the args passed into the invoking template. -- Otherwise, for testing purposes, assume args are being passed directly in. if frame == mw.getCurrentFrame() then origArgs = frame:getParent().args else origArgs = frame end -- Parse the data parameters in the same order that the old {{infobox}} did, so that -- references etc. will display in the expected places. Parameters that depend on -- another parameter are only processed if that parameter is present, to avoid -- phantom references appearing in article reference lists. preprocessSingleArg('child') preprocessSingleArg('bodyclass') preprocessSingleArg('subbox') preprocessSingleArg('bodystyle') preprocessSingleArg('title') preprocessSingleArg('titleclass') preprocessSingleArg('titlestyle') preprocessSingleArg('above') preprocessSingleArg('aboveclass') preprocessSingleArg('abovestyle') preprocessArgs({ {prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}} }, 10) preprocessSingleArg('subheaderstyle') preprocessSingleArg('subheaderclass') preprocessArgs({ {prefix = 'image', depend = {'caption', 'imagerowclass'}} }, 10) preprocessSingleArg('captionstyle') preprocessSingleArg('imagestyle') preprocessSingleArg('imageclass') preprocessArgs({ {prefix = 'header'}, {prefix = 'data', depend = {'label'}}, {prefix = 'rowclass'}, {prefix = 'rowstyle'}, {prefix = 'rowcellstyle'}, {prefix = 'class'}, {prefix = 'dataid'}, {prefix = 'labelid'}, {prefix = 'headerid'}, {prefix = 'rowid'} }, 50) preprocessSingleArg('headerclass') preprocessSingleArg('headerstyle') preprocessSingleArg('labelstyle') preprocessSingleArg('datastyle') preprocessSingleArg('below') preprocessSingleArg('belowclass') preprocessSingleArg('belowstyle') preprocessSingleArg('name') args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent preprocessSingleArg('decat') return _infobox() end return p 2e046db27a7f61675131debae5a131a9dee12195 Template:Infobox 10 49 96 2023-05-29T18:01:05Z star>Alistair3149 0 Load templatestyles through module instead wikitext text/x-wiki {{#invoke:Infobox|infobox}}<noinclude> {{/doc}} <!-- Categories go in the /doc subpage, and interwikis go in Wikidata. --> </noinclude> aaadab5f0433ae495a07ed115145bf7ca42d5c10 Module:String 828 43 84 2023-05-30T20:14:41Z Star>Alistair3149 0 Sync with Wikipedia Scribunto text/plain --[[ This module is intended to provide access to basic string functions. Most of the functions provided here can be invoked with named parameters, unnamed parameters, or a mixture. If named parameters are used, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. Depending on the intended use, it may be advantageous to either preserve or remove such whitespace. Global options ignore_errors: If set to 'true' or 1, any error condition will result in an empty string being returned rather than an error message. error_category: If an error occurs, specifies the name of a category to include with the error message. The default category is [Category:Errors reported by Module String]. no_category: If set to 'true' or 1, no category will be added if an error is generated. Unit tests for this module are available at Module:String/tests. ]] local str = {} --[[ len This function returns the length of the target string. Usage: {{#invoke:String|len|target_string|}} OR {{#invoke:String|len|s=target_string}} Parameters s: The string whose length to report If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. ]] function str.len( frame ) local new_args = str._getParameters( frame.args, {'s'} ) local s = new_args['s'] or '' return mw.ustring.len( s ) end --[[ sub This function returns a substring of the target string at specified indices. Usage: {{#invoke:String|sub|target_string|start_index|end_index}} OR {{#invoke:String|sub|s=target_string|i=start_index|j=end_index}} Parameters s: The string to return a subset of i: The fist index of the substring to return, defaults to 1. j: The last index of the string to return, defaults to the last character. The first character of the string is assigned an index of 1. If either i or j is a negative value, it is interpreted the same as selecting a character by counting from the end of the string. Hence, a value of -1 is the same as selecting the last character of the string. If the requested indices are out of range for the given string, an error is reported. ]] function str.sub( frame ) local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } ) local s = new_args['s'] or '' local i = tonumber( new_args['i'] ) or 1 local j = tonumber( new_args['j'] ) or -1 local len = mw.ustring.len( s ) -- Convert negatives for range checking if i < 0 then i = len + i + 1 end if j < 0 then j = len + j + 1 end if i > len or j > len or i < 1 or j < 1 then return str._error( 'String subset index out of range' ) end if j < i then return str._error( 'String subset indices out of order' ) end return mw.ustring.sub( s, i, j ) end --[[ This function implements that features of {{str sub old}} and is kept in order to maintain these older templates. ]] function str.sublength( frame ) local i = tonumber( frame.args.i ) or 0 local len = tonumber( frame.args.len ) return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) ) end --[[ _match This function returns a substring from the source string that matches a specified pattern. It is exported for use in other modules Usage: strmatch = require("Module:String")._match sresult = strmatch( s, pattern, start, match, plain, nomatch ) Parameters s: The string to search pattern: The pattern or string to find within the string start: The index within the source string to start the search. The first character of the string has index 1. Defaults to 1. match: In some cases it may be possible to make multiple matches on a single string. This specifies which match to return, where the first match is match= 1. If a negative number is specified then a match is returned counting from the last match. Hence match = -1 is the same as requesting the last match. Defaults to 1. plain: A flag indicating that the pattern should be understood as plain text. Defaults to false. nomatch: If no match is found, output the "nomatch" value rather than an error. For information on constructing Lua patterns, a form of [regular expression], see: * http://www.lua.org/manual/5.1/manual.html#5.4.1 * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns ]] -- This sub-routine is exported for use in other modules function str._match( s, pattern, start, match_index, plain_flag, nomatch ) if s == '' then return str._error( 'Target string is empty' ) end if pattern == '' then return str._error( 'Pattern string is empty' ) end start = tonumber(start) or 1 if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then return str._error( 'Requested start is out of range' ) end if match_index == 0 then return str._error( 'Match index is out of range' ) end if plain_flag then pattern = str._escapePattern( pattern ) end local result if match_index == 1 then -- Find first match is simple case result = mw.ustring.match( s, pattern, start ) else if start > 1 then s = mw.ustring.sub( s, start ) end local iterator = mw.ustring.gmatch(s, pattern) if match_index > 0 then -- Forward search for w in iterator do match_index = match_index - 1 if match_index == 0 then result = w break end end else -- Reverse search local result_table = {} local count = 1 for w in iterator do result_table[count] = w count = count + 1 end result = result_table[ count + match_index ] end end if result == nil then if nomatch == nil then return str._error( 'Match not found' ) else return nomatch end else return result end end --[[ match This function returns a substring from the source string that matches a specified pattern. Usage: {{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}} OR {{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index |match=match_number|plain=plain_flag|nomatch=nomatch_output}} Parameters s: The string to search pattern: The pattern or string to find within the string start: The index within the source string to start the search. The first character of the string has index 1. Defaults to 1. match: In some cases it may be possible to make multiple matches on a single string. This specifies which match to return, where the first match is match= 1. If a negative number is specified then a match is returned counting from the last match. Hence match = -1 is the same as requesting the last match. Defaults to 1. plain: A flag indicating that the pattern should be understood as plain text. Defaults to false. nomatch: If no match is found, output the "nomatch" value rather than an error. If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from each string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. If the match_number or start_index are out of range for the string being queried, then this function generates an error. An error is also generated if no match is found. If one adds the parameter ignore_errors=true, then the error will be suppressed and an empty string will be returned on any failure. For information on constructing Lua patterns, a form of [regular expression], see: * http://www.lua.org/manual/5.1/manual.html#5.4.1 * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns ]] -- This is the entry point for #invoke:String|match function str.match( frame ) local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} ) local s = new_args['s'] or '' local start = tonumber( new_args['start'] ) or 1 local plain_flag = str._getBoolean( new_args['plain'] or false ) local pattern = new_args['pattern'] or '' local match_index = math.floor( tonumber(new_args['match']) or 1 ) local nomatch = new_args['nomatch'] return str._match( s, pattern, start, match_index, plain_flag, nomatch ) end --[[ pos This function returns a single character from the target string at position pos. Usage: {{#invoke:String|pos|target_string|index_value}} OR {{#invoke:String|pos|target=target_string|pos=index_value}} Parameters target: The string to search pos: The index for the character to return If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. The first character has an index value of 1. If one requests a negative value, this function will select a character by counting backwards from the end of the string. In other words pos = -1 is the same as asking for the last character. A requested value of zero, or a value greater than the length of the string returns an error. ]] function str.pos( frame ) local new_args = str._getParameters( frame.args, {'target', 'pos'} ) local target_str = new_args['target'] or '' local pos = tonumber( new_args['pos'] ) or 0 if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then return str._error( 'String index out of range' ) end return mw.ustring.sub( target_str, pos, pos ) end --[[ str_find This function duplicates the behavior of {{str_find}}, including all of its quirks. This is provided in order to support existing templates, but is NOT RECOMMENDED for new code and templates. New code is recommended to use the "find" function instead. Returns the first index in "source" that is a match to "target". Indexing is 1-based, and the function returns -1 if the "target" string is not present in "source". Important Note: If the "target" string is empty / missing, this function returns a value of "1", which is generally unexpected behavior, and must be accounted for separatetly. ]] function str.str_find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target'} ) local source_str = new_args['source'] or '' local target_str = new_args['target'] or '' if target_str == '' then return 1 end local start = mw.ustring.find( source_str, target_str, 1, true ) if start == nil then start = -1 end return start end --[[ find This function allows one to search for a target string or pattern within another string. Usage: {{#invoke:String|find|source_str|target_string|start_index|plain_flag}} OR {{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}} Parameters source: The string to search target: The string or pattern to find within source start: The index within the source string to start the search, defaults to 1 plain: Boolean flag indicating that target should be understood as plain text and not as a Lua style regular expression, defaults to true If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. This function returns the first index >= "start" where "target" can be found within "source". Indices are 1-based. If "target" is not found, then this function returns 0. If either "source" or "target" are missing / empty, this function also returns 0. This function should be safe for UTF-8 strings. ]] function str.find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } ) local source_str = new_args['source'] or '' local pattern = new_args['target'] or '' local start_pos = tonumber(new_args['start']) or 1 local plain = new_args['plain'] or true if source_str == '' or pattern == '' then return 0 end plain = str._getBoolean( plain ) local start = mw.ustring.find( source_str, pattern, start_pos, plain ) if start == nil then start = 0 end return start end --[[ replace This function allows one to replace a target string or pattern within another string. Usage: {{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}} OR {{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string| count=replacement_count|plain=plain_flag}} Parameters source: The string to search pattern: The string or pattern to find within source replace: The replacement text count: The number of occurences to replace, defaults to all. plain: Boolean flag indicating that pattern should be understood as plain text and not as a Lua style regular expression, defaults to true ]] function str.replace( frame ) local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } ) local source_str = new_args['source'] or '' local pattern = new_args['pattern'] or '' local replace = new_args['replace'] or '' local count = tonumber( new_args['count'] ) local plain = new_args['plain'] or true if source_str == '' or pattern == '' then return source_str end plain = str._getBoolean( plain ) if plain then pattern = str._escapePattern( pattern ) replace = mw.ustring.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences. end local result if count ~= nil then result = mw.ustring.gsub( source_str, pattern, replace, count ) else result = mw.ustring.gsub( source_str, pattern, replace ) end return result end --[[ simple function to pipe string.rep to templates. ]] function str.rep( frame ) local repetitions = tonumber( frame.args[2] ) if not repetitions then return str._error( 'function rep expects a number as second parameter, received "' .. ( frame.args[2] or '' ) .. '"' ) end return string.rep( frame.args[1] or '', repetitions ) end --[[ escapePattern This function escapes special characters from a Lua string pattern. See [1] for details on how patterns work. [1] https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns Usage: {{#invoke:String|escapePattern|pattern_string}} Parameters pattern_string: The pattern string to escape. ]] function str.escapePattern( frame ) local pattern_str = frame.args[1] if not pattern_str then return str._error( 'No pattern string specified' ) end local result = str._escapePattern( pattern_str ) return result end --[[ count This function counts the number of occurrences of one string in another. ]] function str.count(frame) local args = str._getParameters(frame.args, {'source', 'pattern', 'plain'}) local source = args.source or '' local pattern = args.pattern or '' local plain = str._getBoolean(args.plain or true) if plain then pattern = str._escapePattern(pattern) end local _, count = mw.ustring.gsub(source, pattern, '') return count end --[[ endswith This function determines whether a string ends with another string. ]] function str.endswith(frame) local args = str._getParameters(frame.args, {'source', 'pattern'}) local source = args.source or '' local pattern = args.pattern or '' if pattern == '' then -- All strings end with the empty string. return "yes" end if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then return "yes" else return "" end end --[[ join Join all non empty arguments together; the first argument is the separator. Usage: {{#invoke:String|join|sep|one|two|three}} ]] function str.join(frame) local args = {} local sep for _, v in ipairs( frame.args ) do if sep then if v ~= '' then table.insert(args, v) end else sep = v end end return table.concat( args, sep or '' ) end --[[ Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. ]] function str._getParameters( frame_args, arg_list ) local new_args = {} local index = 1 local value for _, arg in ipairs( arg_list ) do value = frame_args[arg] if value == nil then value = frame_args[index] index = index + 1 end new_args[arg] = value end return new_args end --[[ Helper function to handle error messages. ]] function str._error( error_str ) local frame = mw.getCurrentFrame() local error_category = frame.args.error_category or 'Errors reported by Module String' local ignore_errors = frame.args.ignore_errors or false local no_category = frame.args.no_category or false if str._getBoolean(ignore_errors) then return '' end local error_str = '<strong class="error">String Module Error: ' .. error_str .. '</strong>' if error_category ~= '' and not str._getBoolean( no_category ) then error_str = '[[Category:' .. error_category .. ']]' .. error_str end return error_str end --[[ Helper Function to interpret boolean strings ]] function str._getBoolean( boolean_str ) local boolean_value if type( boolean_str ) == 'string' then boolean_str = boolean_str:lower() if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' or boolean_str == '' then boolean_value = false else boolean_value = true end elseif type( boolean_str ) == 'boolean' then boolean_value = boolean_str else error( 'No boolean value found' ) end return boolean_value end --[[ Helper function that escapes all pattern characters so that they will be treated as plain text. ]] function str._escapePattern( pattern_str ) return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" ) end return str 6df794dd52434e0f6a372c9918f5a9dedd15f579 Category:Category namespace templates 14 6 10 2023-05-30T20:29:23Z Star>Alistair3149 0 Created page with "{{Category header|templates|category namespaces}} [[Category:Templates]]" wikitext text/x-wiki {{Category header|templates|category namespaces}} [[Category:Templates]] 6184a06473d378b690d4f5f4e627f2a40cd941b5 11 10 2024-01-11T08:30:42Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|category namespaces}} [[Category:Templates]] 6184a06473d378b690d4f5f4e627f2a40cd941b5 Module:User error 828 65 128 2023-06-01T04:08:37Z star>Alistair3149 0 Created page with "-------------------------------------------------------------------------------- -- A less intimidating version of the built-in "error()" function, to help -- editors fix their mistakes when transcluding a template. -- -- @see [[wikia:w:c:Dev:Module:User error]] for a similar module. -------------------------------------------------------------------------------- local checkType = require("libraryUtil").checkType; return function (message, ...) checkType("Module:User..." Scribunto text/plain -------------------------------------------------------------------------------- -- A less intimidating version of the built-in "error()" function, to help -- editors fix their mistakes when transcluding a template. -- -- @see [[wikia:w:c:Dev:Module:User error]] for a similar module. -------------------------------------------------------------------------------- local checkType = require("libraryUtil").checkType; return function (message, ...) checkType("Module:User error", 1, message, "string"); local result = mw.text.tag( "strong", { class="error" }, "Error: " .. message ); local categories = {}; for i = 1, select("#", ...) do local category = select(i, ...); checkType("Module:User error", 1 + i, category, "string", true); if (category and category ~= "") then table.insert(categories, "[[Category:" .. category .. "]]"); end end return result .. table.concat(categories); end; a4101fc46477bcd3c5dd899b157bf34b216d820f Module:Mbox 828 66 130 2023-06-06T03:02:53Z star>Alistair3149 0 Scribunto text/plain local libraryUtil = require( 'libraryUtil' ) local checkType = libraryUtil.checkType local mArguments -- lazily initialise [[Module:Arguments]] local mError -- lazily initialise [[Module:Error]] local p = {} --- Helper function to throw error -- -- @param msg string - Error message -- -- @return string - Formatted error message in wikitext local function makeWikitextError( msg ) mError = require( 'Module:Error' ) return mError.error{ message = 'Error: ' .. msg .. '.' } end function p.mbox( frame ) local args = getArgs( frame ) local title = args[1] or args[ 'title' ] local text = args[2] or args[ 'text' ] if not s then return p.makeWikitextError( 'no text specified', 'Template:Mbox#Errors', args.category ) end return p._mbox( title, text, { extraclasses = args.extraclasses, icon = args.icon } ) end function p._mbox( title, text, options ) checkType( '_mbox', 1, title, 'string' ) checkType( '_mbox', 2, text, 'string' ) checkType( '_mbox', 3, options, 'table', true ) options = options or {} local mbox = mw.html.create( 'div' ) local extraclasses if type( options.extraclasses ) == 'string' then extraclasses = options.extraclasses end mbox :attr( 'role', 'presentation' ) :addClass( 'mbox' ) :addClass( extraclasses ) local mboxTitle = mbox:tag( 'div' ):addClass( 'mbox-title' ) if options.icon and type( options.icon ) == 'string' then mboxTitle:tag( 'div' ) :addClass( 'mbox-icon metadata' ) :wikitext( '[[File:' .. options.icon .. '|14px|link=]]' ) :done() :tag( 'div' ) :wikitext( title ) else mboxTitle:wikitext( title ) end mbox:tag( 'div' ) :addClass( 'mbox-text' ) :wikitext( text ) return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Mbox/styles.css' } } .. tostring(mbox) end return p 3ac408bcf509952e70b97e64cb1062fe21f6c4bf Template:Documentation/styles.css 10 53 104 2023-06-06T04:33:22Z star>Alistair3149 0 text text/plain .documentation { display: flex; box-sizing: border-box; flex-direction: column; margin: 1.6rem 0; padding-top: 1.6rem; border-top: 1px solid; border-color: var( --border-color-base ); border-radius: var( --border-radius--medium ); font-size: 0.875rem; } .documentation-header { margin-top: 0; margin-bottom: 0.8rem; color: var( --color-base--emphasized ); font-size: 1.25rem; font-weight: 600; line-height: 1.2; } .documentation-subheader { margin: -0.6rem 0 1.6rem 0; color: var( --color-base--subtle ); font-size: 0.825rem; } .documentation-links { margin: 0.3rem 0; float: right; font-family: monospace; font-size: 0.875rem; font-weight: 400; } .documentation-modulestats { display: flex; align-items: center; justify-content: space-between; } .documentation-modulestats .wikitable{ margin: 0; } /** * Tooltip styles used by DependencyList, * shouldn't be here but it is only used here anyways */ .hatnote-container { position: relative; } .tooltip-trigger { padding: 0.2rem 0.5rem; margin-right: 2px; background: var( --color-primary ); border-radius: 100px; color: #fff; } .tooltip-trigger:hover { background: var( --color-primary--hover ); } .tooltip-content { position: absolute; z-index: 1; right: 0; padding: 15px; background-color: var( --color-surface-1 ); border-radius: var( --border-radius--medium ); box-shadow: 0 14px 28px rgba( 0, 0, 0, 0.06 ), 0 10px 10px rgba( 0, 0, 0, 0.06 ); visibility: hidden; } .tooltip-content > ol { margin-top: 0; margin-left: 1.2rem; } .tooltip-content:hover, .tooltip-trigger:hover + .tooltip-content { visibility: visible; } 7cedb77e3d7d2055318ceaf9b5e24342b73243ce Template:Infobox/doc 10 61 120 2023-06-07T16:27:07Z star>Alistair3149 0 deprecate Template:Wikipedia template wikitext text/x-wiki {{Documentation|fromWikipedia=true}} <!-- EDIT TEMPLATE DOCUMENTATION BELOW THIS LINE --> Please refer to {{t|Infobox}} on Wikipedia for more details <noinclude></noinclude> <includeonly> <!-- Template catergories go here --> [[Category:Infobox templates]] </includeonly> 04b27574c3656318415ace03777bcc2a3c16ef74 Module:Mbox/styles.css 828 67 132 2023-06-09T03:29:19Z star>Alistair3149 0 text text/plain .mbox { position: relative; display: flex; flex-direction: column; margin-top: var( --space-xs ); margin-bottom: var( --space-md ); background-color: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); color: var( --color-base--subtle ); font-size: 0.875rem; line-height: var( --line-height-xs ); } .mbox.mbox-high { /* FIXME: Update back to Citzen CSS var when patched */ background-color: rgba( 221, 51, 51, 0.1 ); } .mbox.mbox-med { /* FIXME: Update back to Citzen CSS var when patched */ background-color: rgba( 255, 204, 51, 0.1 ); } .mbox-title { display: flex; align-items: center; padding: var( --space-sm ) var( --space-md ); } .mbox-icon img { width: 14px; height: auto; margin-right: var( --space-xs ); opacity: 0.5; } .mbox-text { position: absolute; top: 100%; z-index: 10; padding: var( --space-md ); width: 100%; box-sizing: border-box; background-color: var( --color-surface-1 ); border-bottom-left-radius: var( --border-radius--medium ); border-bottom-right-radius: var( --border-radius--medium ); box-shadow: var( --box-shadow-dialog ); opacity: 0; visibility: hidden; } .mbox:hover { /* Merge with popup */ border-bottom-left-radius: 0; border-bottom-right-radius: 0; box-shadow: var( --box-shadow-dialog ); } .mbox:hover .mbox-text { opacity: 1; visibility: visible; } /* Dark mode */ html.skin-citizen-dark .mbox-icon img { filter: invert( 1 ); } 6e8c0951d8f9dcde54a751e8564916bec21071ce Category:SMW templates 14 30 58 2023-06-20T02:34:07Z Star>Alistair3149 0 Created page with "{{Category header|templates|Semantic MediaWiki}} [[Category:Templates]]" wikitext text/x-wiki {{Category header|templates|Semantic MediaWiki}} [[Category:Templates]] a92eae2d4d80d16870caa41abea5041ce8d46b04 59 58 2024-01-11T08:30:52Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|Semantic MediaWiki}} [[Category:Templates]] a92eae2d4d80d16870caa41abea5041ce8d46b04 Module:Format link 828 63 124 2023-06-24T17:00:45Z star>Alistair3149 0 Sync with upstream Scribunto text/plain -- Imported from: https://en.wikipedia.org/wiki/Module:Format_link -------------------------------------------------------------------------------- -- Format link -- -- Makes a wikilink from the given link and display values. Links are escaped -- with colons if necessary, and links to sections are detected and displayed -- with " § " as a separator rather than the standard MediaWiki "#". Used in -- the {{format link}} template. -------------------------------------------------------------------------------- local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg local mArguments -- lazily initialise [[Module:Arguments]] local mError -- lazily initialise [[Module:Error]] local yesno -- lazily initialise [[Module:Yesno]] local p = {} -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function getArgs(frame) -- Fetches the arguments from the parent frame. Whitespace is trimmed and -- blanks are removed. mArguments = require('Module:Arguments') return mArguments.getArgs(frame, {parentOnly = true}) end local function removeInitialColon(s) -- Removes the initial colon from a string, if present. return s:match('^:?(.*)') end local function maybeItalicize(s, shouldItalicize) -- Italicize s if s is a string and the shouldItalicize parameter is true. if s and shouldItalicize then return '<i>' .. s .. '</i>' else return s end end local function parseLink(link) -- Parse a link and return a table with the link's components. -- These components are: -- - link: the link, stripped of any initial colon (always present) -- - page: the page name (always present) -- - section: the page name (may be nil) -- - display: the display text, if manually entered after a pipe (may be nil) link = removeInitialColon(link) -- Find whether a faux display value has been added with the {{!}} magic -- word. local prePipe, display = link:match('^(.-)|(.*)$') link = prePipe or link -- Find the page, if it exists. -- For links like [[#Bar]], the page will be nil. local preHash, postHash = link:match('^(.-)#(.*)$') local page if not preHash then -- We have a link like [[Foo]]. page = link elseif preHash ~= '' then -- We have a link like [[Foo#Bar]]. page = preHash end -- Find the section, if it exists. local section if postHash and postHash ~= '' then section = postHash end return { link = link, page = page, section = section, display = display, } end local function formatDisplay(parsed, options) -- Formats a display string based on a parsed link table (matching the -- output of parseLink) and an options table (matching the input options for -- _formatLink). local page = maybeItalicize(parsed.page, options.italicizePage) local section = maybeItalicize(parsed.section, options.italicizeSection) if (not section) then return page elseif (not page) then return mw.ustring.format('§&nbsp;%s', section) else return mw.ustring.format('%s §&nbsp;%s', page, section) end end local function missingArgError(target) mError = require('Module:Error') return mError.error{message = 'Error: no link or target specified! ([[' .. target .. '#Errors|help]])' } end -------------------------------------------------------------------------------- -- Main functions -------------------------------------------------------------------------------- function p.formatLink(frame) -- The formatLink export function, for use in templates. yesno = require('Module:Yesno') local args = getArgs(frame) local link = args[1] or args.link local target = args[3] or args.target if not (link or target) then return missingArgError('Template:Format link') end return p._formatLink{ link = link, display = args[2] or args.display, target = target, italicizePage = yesno(args.italicizepage), italicizeSection = yesno(args.italicizesection), categorizeMissing = args.categorizemissing } end function p._formatLink(options) -- The formatLink export function, for use in modules. checkType('_formatLink', 1, options, 'table') local function check(key, expectedType) --for brevity checkTypeForNamedArg( '_formatLink', key, options[key], expectedType or 'string', true ) end check('link') check('display') check('target') check('italicizePage', 'boolean') check('italicizeSection', 'boolean') check('categorizeMissing') -- Normalize link and target and check that at least one is present if options.link == '' then options.link = nil end if options.target == '' then options.target = nil end if not (options.link or options.target) then return missingArgError('Module:Format link') end local parsed = parseLink(options.link) local display = options.display or parsed.display local catMissing = options.categorizeMissing local category = '' -- Find the display text if not display then display = formatDisplay(parsed, options) end -- Handle the target option if present if options.target then local parsedTarget = parseLink(options.target) parsed.link = parsedTarget.link parsed.page = parsedTarget.page end -- Test if page exists if a diagnostic category is specified if catMissing and (mw.ustring.len(catMissing) > 0) then local title = nil if parsed.page then title = mw.title.new(parsed.page) end if title and (not title.isExternal) then local success, exists = pcall(function() return title.exists end) if success and not exists then category = mw.ustring.format('[[Category:%s]]', catMissing) end end end -- Format the result as a link if parsed.link == display then return mw.ustring.format('[[:%s]]%s', parsed.link, category) else return mw.ustring.format('[[:%s|%s]]%s', parsed.link, display, category) end end -------------------------------------------------------------------------------- -- Derived convenience functions -------------------------------------------------------------------------------- function p.formatPages(options, pages) -- Formats an array of pages using formatLink and the given options table, -- and returns it as an array. Nil values are not allowed. local ret = {} for i, page in ipairs(pages) do ret[i] = p._formatLink{ link = page, categorizeMissing = options.categorizeMissing, italicizePage = options.italicizePage, italicizeSection = options.italicizeSection } end return ret end return p 410e1254e813fed6fe2f04598836316a197db2d1 Module:Yesno 828 51 100 2023-06-24T17:05:19Z star>Alistair3149 0 Sync with upstream Scribunto text/plain -- Imported from: https://en.wikipedia.org/wiki/Module:Yesno -- Function allowing for consistent treatment of boolean-like wikitext input. -- It works similarly to the template {{yesno}}. return function (val, default) -- If your wiki uses non-ascii characters for any of "yes", "no", etc., you -- should replace "val:lower()" with "mw.ustring.lower(val)" in the -- following line. val = type(val) == 'string' and val:lower() or val if val == nil then return nil elseif val == true or val == 'yes' or val == 'y' or val == 'true' or val == 't' or val == 'on' or val == 'ja' or tonumber(val) == 1 then return true elseif val == false or val == 'no' or val == 'n' or val == 'false' or val == 'f' or val == 'off' or val == 'nein' or tonumber(val) == 0 then return false else return default end end 4cb9790f60303552aa5d331d9ab52f0a3e1f266e Module:Array 828 62 122 2023-06-24T17:23:20Z star>Alistair3149 0 Scribunto text/plain -- Imported from: https://runescape.wiki/w/Module:Array local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local checkTypeMulti = libraryUtil.checkTypeMulti ---@class Array ---@operator call(any[]): Array ---@operator concat(any[]): Array ---@operator concat(number|string|function): string ---@operator unm: Array ---@operator add(number|number[]|Array): Array ---@operator sub(number|number[]|Array): Array ---@operator mul(number|number[]|Array): Array ---@operator div(number|number[]|Array): Array ---@operator pow(number|number[]|Array): Array local Array = { pop = table.remove } Array.__index = Array setmetatable(Array, { __index = table, __call = function (_, arr) return Array.new(arr) end }) -- function Array.__tostring(arr) -- -- local dumpObject = require('Module:Logger').dumpObject -- require 'log' -- local dumpObject = dumpObject -- local mt = getmetatable(arr) -- setmetatable(arr, nil) -- local str = dumpObject(arr, {clean=true, collapseLimit=100}) -- setmetatable(arr, mt) -- return str -- end function Array.__concat(lhs, rhs) if type(lhs) == 'table' and type(rhs) == 'table' then local res = {} for i = 1, #lhs do res[i] = lhs[i] end local l = #lhs for i = 1, #rhs do res[i + l] = rhs[i] end return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) else return tostring(lhs) .. tostring(rhs) end end function Array.__unm(arr) return Array.map(arr, function(x) return -x end) end ---@param lhs number|number[]|Array ---@param rhs number|number[]|Array ---@param funName string ---@param opName string ---@param fun fun(lhs: number, rhs: number): number ---@return Array local function mathTemplate(lhs, rhs, funName, opName, fun) checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'}) checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'}) local res = {} if type(lhs) == 'number' then for i = 1, #rhs do res[i] = fun(lhs, rhs[i]) end elseif type(rhs) == 'number' then for i = 1, #lhs do res[i] = fun(lhs[i], rhs) end else assert(#lhs == #rhs, string.format('Elementwise %s failed because arrays have different sizes (left: %d, right: %d)', opName, #lhs, #rhs)) for i = 1, #lhs do res[i] = fun(lhs[i], rhs[i]) end end return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) end function Array.__add(lhs, rhs) return mathTemplate(lhs, rhs, '__add', 'addition', function(x, y) return x + y end) end function Array.__sub(lhs, rhs) return mathTemplate(lhs, rhs, '__sub', 'substraction', function(x, y) return x - y end) end function Array.__mul(lhs, rhs) return mathTemplate(lhs, rhs, '__mul', 'multiplication', function(x, y) return x * y end) end function Array.__div(lhs, rhs) return mathTemplate(lhs, rhs, '__div', 'division', function(x, y) return x / y end) end function Array.__pow(lhs, rhs) return mathTemplate(lhs, rhs, '__pow', 'exponentiation', function(x, y) return x ^ y end) end function Array.__eq(lhs, rhs) if #lhs ~= #rhs then return false end for i = 1, #lhs do if lhs[i] ~= rhs[i] then return false end end return true end ---Behaviour depends on the value of `fn`: ---* `nil` - Checks that the array doesn't contain any **false** elements. ---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for every element. ---* `number` | `table` | `boolean` - Checks that all elements in `arr` are equal to this value. ---@param arr any[] ---@param fn? any ---@return boolean function Array.all(arr, fn) checkType('Module:Array.all', 1, arr, 'table') if fn == nil then fn = function(item) return item end end if type(fn) ~= 'function' then local val = fn fn = function(item) return item == val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if not fn(arr[i], i) then return false end i = i + 1 end return true end ---Behaviour depends on the value of `fn`: ---* `nil` - Checks that the array contains at least one non **false** element. ---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for at least one element. ---* `number` | `table` | `boolean` - Checks that `arr` contains this value. ---@param arr any[] ---@param fn? any ---@return boolean function Array.any(arr, fn) checkType('Module:Array.any', 1, arr, 'table') if fn == nil then fn = function(item) return item end end if type(fn) ~= 'function' then local val = fn fn = function(item) return item == val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if fn(arr[i], i) then return true end i = i + 1 end return false end ---Recursively removes all metatables. ---@param arr any[] ---@return any[] function Array.clean(arr) checkType('Module:Array.clean', 1, arr, 'table') for i = 1, #arr do if type(arr[i]) == 'table' then Array.clean(arr[i]) end end setmetatable(arr, nil) return arr end ---Make a copy of the input table. Preserves metatables. ---@generic T: any[] ---@param arr T ---@param deep? boolean # Recursively clone subtables if **true**. ---@return T function Array.clone(arr, deep) checkType('Module:Array.clone', 1, arr, 'table') checkType('Module:Array.clone', 2, deep, 'boolean', true) local res = {} for i = 1, #arr do if deep == true and type(arr[i]) == 'table' then res[i] = Array.clone(arr[i], true) else res[i] = arr[i] end end return setmetatable(res, getmetatable(arr)) end ---Check if `arr` contains `val`. ---@param arr any[] ---@param val any ---@return boolean function Array.contains(arr, val) checkType('Module:Array.contains', 1, arr, 'table') for i = 1, #arr do if arr[i] == val then return true end end return false end ---Check if `arr` contains any of the values in the table `t`. ---@param arr any[] ---@param t any[] ---@return boolean function Array.containsAny(arr, t) checkType('Module:Array.containsAny', 1, arr, 'table') checkType('Module:Array.containsAny', 2, t, 'table') local lookupTbl = {} for i = 1, #t do lookupTbl[t[i]] = true end for i = 1, #arr do if lookupTbl[arr[i]] then return true end end return false end ---Check if `arr` contains all values in the table `t`. ---@param arr any[] ---@param t any[] ---@return boolean function Array.containsAll(arr, t) checkType('Module:Array.containsAll', 1, arr, 'table') checkType('Module:Array.containsAll', 2, t, 'table') local lookupTbl = {} local l = #t local trueCount = 0 for i = 1, l do lookupTbl[t[i]] = false end for i = 1, #arr do if lookupTbl[arr[i]] == false then lookupTbl[arr[i]] = true trueCount = trueCount + 1 end if trueCount == l then return true end end return false end ---Convolute two number arrays. ---@generic T: number[] ---@param x T ---@param y T ---@return T function Array.convolve(x, y) checkType('Module:Array.convolve', 1, x, 'table') checkType('Module:Array.convolve', 2, y, 'table') local z = {} local xLen, yLen = #x, #y for j = 1, (xLen + yLen - 1) do local sum = 0 for k = math.max(1, j - yLen + 1), math.min(xLen, j) do sum = sum + x[k] * y[j-k+1] end z[j] = sum end return setmetatable(z, getmetatable(x) or getmetatable(y)) end ---Remove **nil** values from `arr` while preserving order. ---@generic T: any[] ---@param arr T ---@return T function Array.condenseSparse(arr) checkType('Module:Array.condenseSparse', 1, arr, 'table') local keys = {} local res = {} local l = 0 for k in pairs(arr) do l = l + 1 keys[l] = k end table.sort(keys) for i = 1, l do res[i] = arr[keys[i]] end return setmetatable(res, getmetatable(arr)) end ---Behaviour depends on value of `val`: ---* `nil` - Counts the number of non **false** elements. ---* `fun(elem: any): boolean` - Count the number of times the function returned **true**. ---* `boolean` | `number` | `table` - Counts the number of times this value occurs in `arr`. ---@param arr any[] ---@param val? any ---@return integer function Array.count(arr, val) checkType('Module:Array.count', 1, arr, 'table') if val == nil then val = function(item) return item end end if type(val) ~= 'function' then local _val = val val = function(item) return item == _val end end local count = 0 for i = 1, #arr do if val(arr[i]) then count = count + 1 end end return count end ---Differentiate the array ---@generic T: number[] ---@param arr T ---@param order number? # Oder of the differentiation. Default is 1. ---@return T # Length is `#arr - order` function Array.diff(arr, order) checkType('Module:Array.diff', 1, arr, 'table') checkType('Module:Array.diff', 2, order, 'number', true) local res = {} for i = 1, #arr - 1 do res[i] = arr[i+1] - arr[i] end if order and order > 1 then return Array.diff(res, order - 1) end return setmetatable(res, getmetatable(arr)) end ---Loops over `arr` and passes each element as the first argument to `fn`. This function returns nothing. ---@param arr any[] ---@param fn fun(elem: any, i?: integer) function Array.each(arr, fn) checkType('Module:Array.each', 1, arr, 'table') checkType('Module:Array.each', 2, fn, 'function') local i = 1 while arr[i] ~= nil do fn(arr[i], i) i = i + 1 end end ---Makes a copy of `arr` with only elements for which `fn` returned **true**. ---@generic T: any[] ---@param arr T ---@param fn fun(elem: any, i?: integer): boolean ---@return T function Array.filter(arr, fn) checkType('Module:Array.filter', 1, arr, 'table') checkType('Module:Array.filter', 2, fn, 'function') local r = {} local len = 0 local i = 1 while arr[i] ~= nil do if fn(arr[i], i) then len = len + 1 r[len] = arr[i] end i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Find the first elements for which `fn` returns **true**. ---@param arr any[] ---@param fn any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`. ---@param default? any # Value to return if no element passes the test. ---@return any? elem # The first element that passed the test. ---@return integer? i # The index of the item that passed the test. function Array.find(arr, fn, default) checkType('Module:Array.find', 1, arr, 'table') checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) if type(fn) ~= 'function' then local _val = fn fn = function(item) return item == _val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if fn(arr[i], i) then return arr[i], i end i = i + 1 end return default, nil end ---Find the index of `val`. ---@param arr any[] ---@param val any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`. ---@param default? any # Value to return if no element passes the test. ---@return integer? function Array.find_index(arr, val, default) checkType('Module:Array.find_index', 1, arr, 'table') checkTypeMulti('Module:Array.find_index', 2, val, {'function', 'table', 'number', 'boolean'}) if type(val) ~= 'function' then local _val = val val = function(item) return item == _val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if val(arr[i], i) then return i end i = i + 1 end return default end ---Extracts a subset of `arr`. ---@generic T: any[] ---@param arr T ---@param indexes integer|integer[] # Indexes of the elements. ---@return T function Array.get(arr, indexes) checkType('Module:Array.set', 1, arr, 'table') checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'}) if type(indexes) == 'number' then indexes = {indexes} end local res = {} for i = 1, #indexes do res[i] = arr[indexes[i]] end return setmetatable(res, getmetatable(arr)) end ---Integrates the array. Effectively does $\left\{\sum^{n}_{start}{arr[n]} \,\Bigg|\, n \in [start, stop]\right\}$. ---@generic T: number[] ---@param arr T # number[] ---@param start? integer # Index where to start the summation. Defaults to 1. ---@param stop? integer # Index where to stop the summation. Defaults to #arr. ---@return T function Array.int(arr, start, stop) checkType('Module:Array.int', 1, arr, 'table') checkType('Module:Array.int', 2, start, 'number', true) checkType('Module:Array.int', 3, stop, 'number', true) local res = {} start = start or 1 stop = stop or #arr res[1] = arr[start] for i = 1, stop - start do res[i+1] = res[i] + arr[start + i] end return setmetatable(res, getmetatable(arr)) end ---Returns an array with elements that are present in both tables. ---@generic T: any[] ---@param arr1 T ---@param arr2 T ---@return T function Array.intersect(arr1, arr2) checkType('Module:Array.intersect', 1, arr1, 'table') checkType('Module:Array.intersect', 2, arr2, 'table') local arr2Elements = {} local res = {} local len = 0 Array.each(arr2, function(item) arr2Elements[item] = true end) Array.each(arr1, function(item) if arr2Elements[item] then len = len + 1 res[len] = item end end) return setmetatable(res, getmetatable(arr1) or getmetatable(arr2)) end ---Checks if the two inputs have at least one element in common. ---@param arr1 any[] ---@param arr2 any[] ---@return boolean function Array.intersects(arr1, arr2) checkType('Module:Array.intersects', 1, arr1, 'table') checkType('Module:Array.intersects', 2, arr2, 'table') local small = {} local large if #arr1 <= #arr2 then Array.each(arr1, function(item) small[item] = true end) large = arr2 else Array.each(arr2, function(item) small[item] = true end) large = arr1 end return Array.any(large, function(item) return small[item] end) end ---Inserts values into `arr`. ---@generic T: any[] ---@param arr T ---@param val any # If `val` is an array and `unpackVal` is **true** then the individual elements of `val` are inserted. ---@param index? integer # Location to start the insertion. Default is at the end of `arr`. ---@param unpackVal? boolean # Default is **false**. ---@return T ---@overload fun(arr: T, val: any, unpackVal: boolean): T function Array.insert(arr, val, index, unpackVal) checkType('Module:Array.insert', 1, arr, 'table') checkTypeMulti('Module:Array.insert', 3, index, {'number', 'boolean', 'nil'}) checkType('Module:Array.insert', 4, unpackVal, 'boolean', true) if type(index) == 'boolean' then unpackVal, index = index, nil end local len = #arr index = index or (len + 1) local mt = getmetatable(arr) setmetatable(arr, nil) if type(val) == 'table' and unpackVal then local len2 = #val for i = 0, len - index do arr[len + len2 - i] = arr[len - i] end for i = 0, len2 - 1 do arr[index + i] = val[i + 1] end else table.insert(arr, index, val) end return setmetatable(arr, mt) end ---Returns the last element of `arr`. ---@param arr any[] ---@param offset? integer ---@return any function Array.last(arr, offset) checkType('Module:Array.last', 1, arr, 'table') checkType('Module:Array.last', 2, offset, 'number', true) return arr[#arr + offset] end ---Returns a new table were each element of `arr` is modified by `fn`. ---@generic T: any[] ---@param arr T ---@param fn fun(elem: any, i?: integer): any # First argument is the current element, the second argument is the index of the current element. ---@return T function Array.map(arr, fn) checkType('Module:Array.map', 1, arr, 'table') checkType('Module:Array.map', 2, fn, 'function') local len = 0 local r = {} local i = 1 while arr[i] ~= nil do local tmp = fn(arr[i], i) if tmp ~= nil then len = len + 1 r[len] = tmp end i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Find the element for which `fn` returned the largest value. ---@param arr any[] ---@param fn fun(elem: any): any # The returned value needs to be comparable using the `<` operator. ---@return any elem # The element with the largest `fn` value. ---@return integer i # The index of this element. function Array.max_by(arr, fn) checkType('Module:Array.max_by', 1, arr, 'table') checkType('Module:Array.max_by', 2, fn, 'function') return unpack(Array.reduce(arr, function(new, old, i) local y = fn(new) return y > old[2] and {new, y, i} or old end, {nil, -math.huge})) end ---Find the largest value in the array. ---@param arr any[] # The values need to be comparable using the `<` operator. ---@return any elem ---@return integer i # The index of the largest value. function Array.max(arr) checkType('Module:Array.max', 1, arr, 'table') local val, _, i = Array.max_by(arr, function(x) return x end) return val, i end ---Find the smallest value in the array. ---@param arr any[] # The values need to be comparable using the `<` operator. ---@return any elem ---@return integer i # The index of the smallest value. function Array.min(arr) checkType('Module:Array.min', 1, arr, 'table') local val, _, i = Array.max_by(arr, function(x) return -x end) return val, i end ---Turn the input table into an Array. This makes it possible to use the colon `:` operator to access the Array methods. --- ---It also enables the use of math operators with the array. ---``` ---local x = arr.new{ 1, 2, 3 } ---local y = arr{ 4, 5, 6 } -- Alternative notation --- ---print( -x ) --> { -1, -2, -3 } ---print( x + 2 ) --> { 3, 4, 5 } ---print( x - 2 ) --> { -1, 0, 1 } ---print( x * 2 ) --> { 2, 4, 6 } ---print( x / 2 ) --> { 0.5, 1, 1.5 } ---print( x ^ 2 ) --> { 1, 4, 9 } --- ---print( x + y ) --> { 5, 7, 9 } ---print( x .. y ) --> { 1, 2, 3, 4, 5, 6 } ---print( (x .. y):reject{3, 4, 5} ) --> { 1, 2, 6 } ---print( x:sum() ) --> 6 --- ---print( x:update( {1, 3}, y:get{2, 3} * 2 ) ) --> { 10, 2, 12 } ---``` ---@param arr? any[] ---@return Array function Array.new(arr) local obj = arr or {} for _, v in pairs(obj) do if type(v) == 'table' then Array.new(v) end end if getmetatable(obj) == nil then setmetatable(obj, Array) end return obj end ---Creates an object that returns a value that is `step` higher than the previous value each time it gets called. --- ---The stored value can be read without incrementing by reading the `val` field. --- ---A new stored value can be set through the `val` field. --- ---A new step size can be set through the `step` field. ---``` ---local inc = arr.newIncrementor(10, 5) ---print( inc() ) --> 10 ---print( inc() ) --> 15 ---print( inc.val ) --> 15 ---inc.val = 100 ---inc.step = 20 ---print( inc.val ) --> 100 ---print( inc() ) --> 120 ---``` ---@param start? number # Default is 1. ---@param step? number # Default is 1. ---@return Incrementor function Array.newIncrementor(start, step) checkType('Module:Array.newIncrementor', 1, start, 'number', true) checkType('Module:Array.newIncrementor', 2, step, 'number', true) step = step or 1 local n = (start or 1) - step ---@class Incrementor local obj = {} return setmetatable(obj, { __call = function() n = n + step return n end, __tostring = function() return n end, __index = function() return n end, __newindex = function(self, k, v) if k == 'step' and type(v) == 'number' then step = v elseif type(v) == 'number' then n = v end end, __concat = function(x, y) return tostring(x) .. tostring(y) end }) end ---Returns a range of numbers. ---@param start number # Start value inclusive. ---@param stop number # Stop value inclusive for integers, exclusive for floats. ---@param step? number # Default is 1. ---@return Array ---@overload fun(stop: number): Array function Array.range(start, stop, step) checkType('Module:Array.range', 1, start, 'number') checkType('Module:Array.range', 2, stop, 'number', true) checkType('Module:Array.range', 3, step, 'number', true) local arr = {} local len = 0 if not stop then stop = start start = 1 end for i = start, stop, step or 1 do len = len + 1 arr[len] = i end return setmetatable(arr, Array) end ---Condenses the array into a single value. --- ---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element. --- ---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element. ---``` ---local t = { 1, 2, 3, 4 } ---local sum = arr.reduce( t, function(elem, acc) return acc + elem end ) -- sum == 10 ---``` ---@param arr any[] ---@param fn fun(elem: any, acc: any, i?: integer): any # The result of this function becomes the `acc` for the next element. ---@param accumulator? any ---@return any # This is the last accumulator value. function Array.reduce(arr, fn, accumulator) checkType('Module:Array.reduce', 1, arr, 'table') checkType('Module:Array.reduce', 2, fn, 'function') local acc = accumulator local i = 1 if acc == nil then acc = arr[1] i = 2 end while arr[i] ~= nil do acc = fn(arr[i], acc, i) i = i + 1 end return acc end ---Make a copy off `arr` with certain values removed. --- ---Behaviour for different values of `val`: ---* `boolean` | `number` - Remove values equal to this. ---* `table` - Remove all values in this table. ---* `fun(elem: any, i?: integer): boolean` - Remove elements for which the functions returns **true**. ---@generic T: any[] ---@param arr T ---@param val table|function|number|boolean ---@return T function Array.reject(arr, val) checkType('Module:Array.reject', 1, arr, 'table') checkTypeMulti('Module:Array.reject', 2, val, {'function', 'table', 'number', 'boolean'}) if type(val) ~= 'function' and type(val) ~= 'table' then val = {val} end local r = {} local len = 0 if type(val) == 'function' then local i = 1 while arr[i] ~= nil do if not val(arr[i], i) then len = len + 1 r[len] = arr[i] end i = i + 1 end else local rejectMap = {} Array.each(val --[[@as any[] ]], function(item) rejectMap[item] = true end) local i = 1 while arr[i] ~= nil do if not rejectMap[arr[i]] then len = len + 1 r[len] = arr[i] end i = i + 1 end end return setmetatable(r, getmetatable(arr)) end ---Returns an Array with `val` repeated `n` times. ---@param val any ---@param n integer ---@return Array function Array.rep(val, n) checkType('Module:Array.rep', 2, n, 'number') local r = {} for i = 1, n do r[i] = val end return setmetatable(r, Array) end ---Condenses the array into a single value while saving every accumulator value. --- ---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element. --- ---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element. ---``` ---local t = { 1, 2, 3, 4 } ---local x = arr.scan( t, function(elem, acc) return acc + elem end ) -- x = { 1, 3, 6, 10 } ---``` ---@generic T: any[] ---@param arr T ---@param fn fun(elem: any, acc: any, i?: integer): any # Returned value becomes the accumulator for the next element. ---@param accumulator? any ---@return T function Array.scan(arr, fn, accumulator) checkType('Module:Array.scan', 1, arr, 'table') checkType('Module:Array.scan', 2, fn, 'function') local acc = accumulator local r = {} local i = 1 while arr[i] ~= nil do if i == 1 and not accumulator then acc = arr[i] else acc = fn(arr[i], acc, i) end r[i] = acc i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Update a range of index with a range of values. --- ---If if only one value is given but multiple indexes than that value is set for all those indexes. --- ---If `values` is a table then it must of the same length as `indexes`. ---@generic T: any[] ---@param arr T ---@param indexes integer|integer[] ---@param values any|any[] ---@return T function Array.set(arr, indexes, values) checkType('Module:Array.set', 1, arr, 'table') checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'}) local mt = getmetatable(arr) setmetatable(arr, nil) if type(indexes) == 'number' then indexes = {indexes} end if type(values) == 'table' then assert(#indexes == #values, string.format("Module:Array.set: 'indexes' and 'values' arrays are not equal length (#indexes = %d, #values = %d)", #indexes, #values)) for i = 1, #indexes do arr[indexes[i]] = values[i] end else for i = 1, #indexes do arr[indexes[i]] = values end end return setmetatable(arr, mt) end ---Extract a subtable from `arr`. ---@generic T: any[] ---@param arr T ---@param start integer # Start index. Use negative values to count form the end of the array. ---@param stop integer # Stop index. Use negative values to count form the end of the array. ---@return T ---@overload fun(arr: T, stop: integer): T function Array.slice(arr, start, stop) checkType('Module:Array.slice', 1, arr, 'table') checkType('Module:Array.slice', 2, start, 'number', true) checkType('Module:Array.slice', 3, stop, 'number', true) start = start or #arr if start < 0 then start = #arr + start end if stop == nil then stop = start start = 1 end if stop < 0 then stop = #arr + stop end local r = {} local len = 0 for i = start, stop do len = len + 1 r[len] = arr[i] end return setmetatable(r, getmetatable(arr)) end ---Split `arr` into two arrays. ---@generic T: any[] ---@param arr T ---@param index integer # Index to split on. ---@return T x # [1, index] ---@return T y # [index + 1, #arr] function Array.split(arr, index) checkType('Module:Array.split', 1, arr, 'table') checkType('Module:Array.split', 2, index, 'number') local x = {} local y = {} for i = 1, #arr do table.insert(i <= index and x or y, arr[i]) end return setmetatable(x, getmetatable(arr)), setmetatable(y, getmetatable(arr)) end ---Returns the sum of all elements of `arr`. ---@param arr number[] ---@return number function Array.sum(arr) checkType('Module:Array.sum', 1, arr, 'table') local res = 0 for i = 1, #arr do res = res + arr[i] end return res end ---Extract a subtable from `arr`. ---@generic T: any[] ---@param arr T ---@param count integer # Length of the subtable. ---@param start? integer # Start index. Default is 1. ---@return T function Array.take(arr, count, start) checkType('Module:Array.take', 1, arr, 'table') checkType('Module:Array.take', 2, count, 'number') checkType('Module:Array.take', 3, start, 'number', true) local x = {} start = start or 1 for i = start, math.min(#arr, count + start - 1) do table.insert(x, arr[i]) end return setmetatable(x, getmetatable(arr)) end ---Extract a subtable from `arr`. ---``` ---local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ---local x = arr.take_every( t, 2 ) --> x = { 1, 3, 5, 7, 9 } ---local x = arr.take_every( t, 2, 3 ) --> x = { 1, 3, 5 } ---local x = arr.take_every( t, 2, 3, 2 ) --> x = { 2, 4, 6 } --- ``` ---@generic T: any[] ---@param arr T ---@param n integer # Step size. ---@param start? integer # Start index. ---@param count? integer # Max amount of elements to get. ---@return T function Array.take_every(arr, n, start, count) checkType('Module:Array.take_every', 1, arr, 'table') checkType('Module:Array.take_every', 2, n, 'number') checkType('Module:Array.take_every', 3, start, 'number', true) checkType('Module:Array.take_every', 4, count, 'number', true) count = count or #arr local r = {} local len = 0 local i = start or 1 while arr[i] ~= nil and len < count do len = len + 1 r[len] = arr[i] i = i + n end return setmetatable(r, getmetatable(arr)) end ---Return a new table with all duplicates removed. ---@generic T: any[] ---@param arr T ---@param fn? fun(elem: any): any # Function to generate an id for each element. The result will then contain elements that generated unique ids. ---@return T function Array.unique(arr, fn) checkType('Module:Array.unique', 1, arr, 'table') checkType('Module:Array.unique', 2, fn, 'function', true) fn = fn or function(item) return item end local r = {} local len = 0 local hash = {} local i = 1 while arr[i] ~= nil do local id = fn(arr[i]) if not hash[id] then len = len + 1 r[len] = arr[i] hash[id] = true end i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Combine elements with the same index from multiple arrays. ---``` ---local x = {1, 2, 3} ---local y = {4, 5, 6, 7} ---local z = arr.zip( x, y ) --> z = { { 1, 4 }, { 2, 5 }, { 3, 6 }, { 7 } } ---``` ---@param ... any[] ---@return Array function Array.zip(...) local arrs = { ... } checkType('Module:Array.zip', 1, arrs[1], 'table') local r = {} local _, longest = Array.max_by(arrs, function(arr) return #arr end) for i = 1, longest do local q = {} for j = 1, #arrs do table.insert(q, arrs[j][i]) end table.insert(r, setmetatable(q, Array)) end return setmetatable(r, Array) end -- Range indexing has a performance impact so this is placed in a separate subclass Array.RI_mt = {} for k, v in pairs(Array) do Array.RI_mt[k] = v end function Array.RI_mt.__index(t, k) if type(k) == 'table' then local res = {} for i = 1, #k do res[i] = t[k[i]] end return setmetatable(res, Array) else return Array[k] end end function Array.RI_mt.__newindex(t, k, v) if type(k) == 'table' then if type(v) == 'table' then for i = 1, #k do t[k[i]] = v[i] end else for i = 1, #k do t[k[i]] = v end end else rawset(t, k, v) end end ---Enable range indexing on the input array. --- ---This has a performance impact on reads and writes to the table. ---``` ---local t = arr{10, 11, 12, 13, 14, 15}:ri() ---print( t[{2, 3}] ) --> { 11, 12 } ---``` ---@param arr any[] ---@param recursive? boolean # Default is false. ---@return Array function Array.ri(arr, recursive) checkType('Module:Array.ri', 1, arr, 'table') checkType('Module:Array.ri', 2, recursive, 'boolean', true) arr = arr or {} if recursive then for _, v in pairs(arr) do if type(v) == 'table' then Array.ri(v, true) end end end if getmetatable(arr) == nil or getmetatable(arr) == Array then setmetatable(arr, Array.RI_mt) end return arr end ---Globally enable range indexing on all Array objects by default. ---@param set boolean function Array.allwaysAllowRangeIndexing(set) checkType('Module:Array.allwaysAllowRangeIndexing', 1, set, 'boolean') if set then Array.__index = Array.RI_mt.__index Array.__newindex = Array.RI_mt.__newindex else Array.__index = Array Array.__newindex = nil end end return Array c81adb59b4d3a4728952df3ad8d681664333a799 Module:Paramtest 828 57 112 2023-06-24T17:31:26Z star>Alistair3149 0 Scribunto text/plain -- Imported from: https://runescape.wiki/w/Module:Paramtest --[[ {{Helper module |name=Paramtest |fname1 = is_empty(arg) |ftype1 = String |fuse1 = Returns true if arg is not defined or contains only whitespace |fname2 = has_content(arg) |ftype2 = String |fuse2 = Returns true if arg exists and does not only contain whitespace |fname3 = default_to(arg1,arg2) |ftype3 = String, Any value |fuse3 = If arg1 exists and does not only contain whitespace, the function returns arg1, otherwise returns arg2 |fname4 = defaults{ {arg1,arg2},...} |ftype4 = {String, Any value}... |fuse4 = Does the same as <code>default_to()</code> run over every table passed |fname5 = table_is_empty(arg) |ftype5 = Table |fuse5 = Returns true if the table has no content, it does not check if the content of the table contains anything |fname6 = table_has_content(arg) |ftype6 = Table |fuse6 = returns true if the table has content, it does not check if the content of the table contains anything }} --]] local checkType, checkTypeForNamedArg do local _libraryUtil = require("libraryUtil"); checkType = _libraryUtil.checkType; checkTypeForNamedArg = _libraryUtil.checkTypeForNamedArg; end -- -- Tests basic properties of parameters -- local p = {} -- -- Tests if the parameter is empty, all white space, or undefined -- function p.is_empty(arg) return not string.find(arg or '', '%S') end -- -- Tests if the table parameter is empty -- function p.table_is_empty(arg) for _, _ in pairs(arg) do return false end return true end -- -- Returns the parameter if it has any content, the default (2nd param) -- function p.default_to(arg, default) if string.find(arg or '', '%S') then return arg else return default end end -- -- Returns a list of paramaters if it has any content, or the default -- function p.defaults(args) checkType("defaults", 1, args, "table"); local ret = {} for i, v in ipairs(args) do checkTypeForNamedArg("defaults", i, v, "table"); ret[i] = p.default_to(v[1], v[2]); end return unpack(ret, 1, #args); end -- -- Tests if the parameter has content -- The same as !is_empty, but this is more readily clear -- function p.has_content(arg) return string.find(arg or '', '%S') end -- -- Tests if the table parameter has content -- The same as !table_is_empty, but this is more readily clear -- function p.table_has_content(arg) for _, _ in pairs(arg) do return true end return false end -- -- uppercases first letter -- function p.ucfirst(arg) if not arg or arg:len() == 0 then return nil elseif arg:len() == 1 then return arg:upper() else return arg:sub(1,1):upper() .. arg:sub(2) end end -- -- uppercases first letter, lowercases everything else -- function p.ucflc(arg) if not arg or arg:len() == 0 then return nil elseif arg:len() == 1 then return arg:upper() else return arg:sub(1,1):upper() .. arg:sub(2):lower() end end return p d69422a8379e1fcb190fe16e6d212071b9caa1dc Module:Hatnote 828 41 80 2023-07-11T03:30:11Z Star>Alistair3149 0 Sync with upstream Scribunto text/plain -------------------------------------------------------------------------------- -- Module:Hatnote -- -- -- -- This module produces hatnote links and links to related articles. It -- -- implements the {{hatnote}} and {{format link}} meta-templates and includes -- -- helper functions for other Lua hatnote modules. -- -------------------------------------------------------------------------------- local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local mArguments -- lazily initialise [[Module:Arguments]] local yesno -- lazily initialise [[Module:Yesno]] local p = {} -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function getArgs(frame) -- Fetches the arguments from the parent frame. Whitespace is trimmed and -- blanks are removed. mArguments = require('Module:Arguments') return mArguments.getArgs(frame, {parentOnly = true}) end local function removeInitialColon(s) -- Removes the initial colon from a string, if present. return s:match('^:?(.*)') end function p.defaultClasses(inline) -- Provides the default hatnote classes as a space-separated string; useful -- for hatnote-manipulation modules like [[Module:Hatnote group]]. return (inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' .. 'navigation-not-searchable' end function p.disambiguate(page, disambiguator) -- Formats a page title with a disambiguation parenthetical, -- i.e. "Example" → "Example (disambiguation)". checkType('disambiguate', 1, page, 'string') checkType('disambiguate', 2, disambiguator, 'string', true) disambiguator = disambiguator or 'disambiguation' return mw.ustring.format('%s (%s)', page, disambiguator) end function p.findNamespaceId(link, removeColon) -- Finds the namespace id (namespace number) of a link or a pagename. This -- function will not work if the link is enclosed in double brackets. Colons -- are trimmed from the start of the link by default. To skip colon -- trimming, set the removeColon parameter to false. checkType('findNamespaceId', 1, link, 'string') checkType('findNamespaceId', 2, removeColon, 'boolean', true) if removeColon ~= false then link = removeInitialColon(link) end local namespace = link:match('^(.-):') if namespace then local nsTable = mw.site.namespaces[namespace] if nsTable then return nsTable.id end end return 0 end function p.makeWikitextError(msg, helpLink, addTrackingCategory, title) -- Formats an error message to be returned to wikitext. If -- addTrackingCategory is not false after being returned from -- [[Module:Yesno]], and if we are not on a talk page, a tracking category -- is added. checkType('makeWikitextError', 1, msg, 'string') checkType('makeWikitextError', 2, helpLink, 'string', true) yesno = require('Module:Yesno') title = title or mw.title.getCurrentTitle() -- Make the help link text. local helpText if helpLink then helpText = ' ([[' .. helpLink .. '|help]])' else helpText = '' end -- Make the category text. local category if not title.isTalkPage -- Don't categorise talk pages and title.namespace ~= 2 -- Don't categorise userspace and yesno(addTrackingCategory) ~= false -- Allow opting out then category = 'Hatnote templates with errors' category = mw.ustring.format( '[[%s:%s]]', mw.site.namespaces[14].name, category ) else category = '' end return mw.ustring.format( '<strong class="error">Error: %s%s.</strong>%s', msg, helpText, category ) end local curNs = mw.title.getCurrentTitle().namespace p.missingTargetCat = --Default missing target category, exported for use in related modules ((curNs == 0) or (curNs == 14)) and 'Articles with hatnote templates targeting a nonexistent page' or nil function p.quote(title) --Wraps titles in quotation marks. If the title starts/ends with a quotation --mark, kerns that side as with {{-'}} local quotationMarks = { ["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true } local quoteLeft, quoteRight = -- Test if start/end are quotation marks quotationMarks[string.sub(title, 1, 1)], quotationMarks[string.sub(title, -1, -1)] if quoteLeft or quoteRight then title = mw.html.create("span"):wikitext(title) end if quoteLeft then title:css("padding-left", "0.15em") end if quoteRight then title:css("padding-right", "0.15em") end return '"' .. tostring(title) .. '"' end -------------------------------------------------------------------------------- -- Hatnote -- -- Produces standard hatnote text. Implements the {{hatnote}} template. -------------------------------------------------------------------------------- local function decorateHatnote(hatnote, options) local function getIcon(filename) local html = '' if type(filename) == 'string' then local icon = mw.html.create('span') icon :addClass('hatnote-icon') :addClass('metadata') :wikitext('[[File:' .. filename .. '|14px|link=]]') :done() html = tostring(icon) end return html end local container = mw.html.create('div') container :addClass('hatnote-container') :wikitext(getIcon(options.icon)) :wikitext(tostring(hatnote)) :done() return container end function p.hatnote(frame) local args = getArgs(frame) local s = args[1] if not s then return p.makeWikitextError( 'no text specified', 'Template:Hatnote#Errors', args.category ) end return p._hatnote(s, { extraclasses = args.extraclasses, selfref = args.selfref }) end function p._hatnote(s, options) checkType('_hatnote', 1, s, 'string') checkType('_hatnote', 2, options, 'table', true) options = options or {} local inline = options.inline local hatnote = mw.html.create(inline == 1 and 'span' or 'div') local extraclasses if type(options.extraclasses) == 'string' then extraclasses = options.extraclasses end hatnote :attr('role', 'note') :addClass(p.defaultClasses(inline)) :addClass(extraclasses) :addClass(options.selfref and 'selfref' or nil) :wikitext(s) -- Decorate WP hatnote to SCW standard hatnote = decorateHatnote(hatnote, options) return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' } } .. tostring(hatnote) end return p 7e322cb6950c0f36959bceccc679cc8f52959f7c Module:DependencyList 828 55 108 2023-07-13T23:58:12Z star>Alistair3149 0 Scribunto text/plain require("strict"); local p = {} local libraryUtil = require( 'libraryUtil' ) local arr = require( 'Module:Array' ) local yn = require( 'Module:Yesno' ) local param = require( 'Module:Paramtest' ) local dpl = require( 'Module:DPLlua' ) local userError = require("Module:User error") local mHatnote = require('Module:Hatnote') local mHatlist = require('Module:Hatnote list') local moduleIsUsed = false local COLLAPSE_LIST_LENGTH_THRESHOLD = 1 local MAX_DYNAMIC_REQUIRE_LIST_LENGTH = 30 local dynamicRequireListQueryCache = {} local builtins = { --[[ ["libraryUtil"] = { link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#libraryUtil", categories = {}, } ]] ["strict"] = { link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#strict", categories = { "Strict mode modules" }, }, }; --- Used in case 'require( varName )' is found. Attempts to find a string value stored in 'varName'. ---@param content string The content of the module to search in ---@param varName string ---@return string local function substVarValue( content, varName ) local res = content:match( varName .. '%s*=%s*(%b""%s-%.*)' ) or content:match( varName .. "%s*=%s*(%b''%s-%.*)" ) or '' if res:find( '^(["\'])[Mm]odule:[%S]+%1' ) and not res:find( '%.%.' ) and not res:find( '%%%a' ) then return mw.text.trim( res ) else return '' end end ---@param capture string ---@param content string The content of the module to search in ---@return string local function extractModuleName( capture, content ) capture = capture:gsub( '^%(%s*(.-)%s*%)$', '%1' ) if capture:find( '^(["\']).-%1$' ) then -- Check if it is already a pure string return capture elseif capture:find( '^[%a_][%w_]*$' ) then -- Check if if is a single variable return substVarValue( content, capture ) end return capture end ---@param str string ---@return string local function formatPageName( str ) local name = mw.text.trim(str) :gsub( '^([\'\"])(.-)%1$', function(_, x) return x end ) -- Only remove quotes at start and end of string if both are the same type :gsub( '_', ' ' ) :gsub( '^.', string.upper ) :gsub( ':.', string.upper ) return name end ---@param str string ---@return string local function formatModuleName( str, allowBuiltins ) if allowBuiltins then local name = mw.text.trim(str) -- Only remove quotes at start and end of string if both are the same type :gsub([[^(['"])(.-)%1$]], function(_, x) return x end); local builtin = builtins[name]; if builtin then return builtin.link .. "|" .. name, builtin; end end local module = formatPageName( str ) if not string.find( module, '^[Mm]odule:' ) then module = 'Module:' .. module end return module end local function dualGmatch( str, pat1, pat2 ) local f1 = string.gmatch( str, pat1 ) local f2 = string.gmatch( str, pat2 ) return function() return f1() or f2() end end --- Used in case a construct like 'require( "Module:wowee/" .. isTheBest )' is found. --- Will return a list of pages which satisfy this pattern where 'isTheBest' can take any value. ---@param query string ---@return string[] Sequence of strings local function getDynamicRequireList( query ) local isDynamic = true; if query:find( '%.%.' ) then query = mw.text.split( query, '..', true ) query = arr.map( query, function(x) return mw.text.trim(x) end ) query = arr.map( query, function(x) return (x:match('^[\'\"](.-)[\'\"]$') or '%') end ) query = table.concat( query ) else local _; _, query = query:match( '(["\'])(.-)%1' ) if query == nil then return {}, isDynamic end local replacements; query, replacements = query:gsub( '%%%a', '%%' ) if replacements == 0 then isDynamic = false; end end query = query:gsub( '^[Mm]odule:', '' ) if query:find( '^[Dd]ata/' ) then return { 'Module:' .. query }, isDynamic; -- This format will later be used by formatDynamicQueryLink() end if dynamicRequireListQueryCache[ query ] then return dynamicRequireListQueryCache[ query ], isDynamic; end local list = dpl.ask{ namespace = 'Module', titlematch = query, nottitlematch = '%/doc|'..query..'/%', distinct = 'strict', ignorecase = true, ordermethod = 'title', count = MAX_DYNAMIC_REQUIRE_LIST_LENGTH + 1, skipthispage = 'no', allowcachedresults = true, cacheperiod = 604800 -- One week } if #list > MAX_DYNAMIC_REQUIRE_LIST_LENGTH then list = { 'Module:' .. query } end dynamicRequireListQueryCache[ query ] = list return list, isDynamic; end --- Returns a list of modules loaded and required by module 'moduleName'. ---@param moduleName string ---@param searchForUsedTemplates boolean ---@return string[], string[], string[], string[] local function getRequireList( moduleName, searchForUsedTemplates ) local content = mw.title.new( moduleName ):getContent() local requireList = arr{} local loadDataList = arr{} local usedTemplateList = arr{} local dynamicRequirelist = arr{} local dynamicLoadDataList = arr{} local extraCategories = arr{} assert( content ~= nil, string.format( '%s does not exist', moduleName ) ) content = content:gsub( '%-%-%[(=-)%[.-%]%1%]', '' ):gsub( '%-%-[^\n]*', '' ) -- Strip comments for match in dualGmatch( content, 'require%s*(%b())', 'require%s*((["\'])%s*[Mm]odule:.-%2)' ) do match = mw.text.trim( match ) match = extractModuleName( match, content ) if match:find( '%.%.' ) or match:find( '%%%a' ) then for _, x in ipairs( getDynamicRequireList( match ) ) do table.insert( dynamicRequirelist, x ) end elseif match ~= '' then local builtin; match, builtin = formatModuleName( match, true ) table.insert( requireList, match ) if builtin then local builtinCategories = builtin.categories; if type(builtinCategories) == "table" then for _, x in ipairs(builtinCategories) do table.insert(extraCategories, x); end end end end end for match in dualGmatch( content, 'mw%.loadData%s*(%b())', 'mw%.loadData%s*((["\'])%s*[Mm]odule:.-%2)' ) do match = mw.text.trim( match ) match = extractModuleName( match, content ) if match:find( '%.%.' ) or match:find( '%%%a' ) then for _, x in ipairs( getDynamicRequireList( match ) ) do table.insert( dynamicLoadDataList, x ) end elseif match ~= '' then match = formatModuleName( match, true ) table.insert( loadDataList, match ) end end for match in dualGmatch( content, 'mw%.loadJsonData%s*(%b())', 'mw%.loadJsonData%s*((["\'])%s*[Mm]odule:.-%2)' ) do match = mw.text.trim( match ) match = extractModuleName( match, content ) if match:find( '%.%.' ) or match:find( '%%%a' ) then for _, x in ipairs( getDynamicRequireList( match ) ) do table.insert( dynamicLoadDataList, x ) end elseif match ~= '' then match = formatModuleName( match, true ) table.insert( loadDataList, match ) end end for func, match in string.gmatch( content, 'pcall%s*%(([^,]+),([^%),]+)' ) do func = mw.text.trim( func ) match = mw.text.trim( match ) local dynList, isDynamic; if func == 'require' then dynList, isDynamic = getDynamicRequireList(match); if (isDynamic == false and #dynList == 1) then table.insert(requireList, dynList[1]); else for _, x in ipairs(dynList) do table.insert( dynamicRequirelist, x ) end end elseif func == 'mw.loadData' then dynList, isDynamic = getDynamicRequireList(match); if (isDynamic == false and #dynList == 1) then table.insert(loadDataList, dynList[1]); else for _, x in ipairs(dynList) do table.insert( dynamicLoadDataList, x ) end end end end if searchForUsedTemplates then for preprocess in string.gmatch( content, ':preprocess%s*(%b())' ) do local function recursiveGMatch( str, pat ) local list = {} local i = 0 repeat for match in string.gmatch( list[i] or str, pat ) do table.insert( list, match ) end i = i + 1 until i > #list or i > 100 i = 0 return function() i = i + 1 return list[i] end end for template in recursiveGMatch( preprocess, '{(%b{})}' ) do local name = string.match( template, '{(.-)[|{}]' ) if name ~= '' then if name:find( ':' ) then local ns = name:match( '^(.-):' ) if arr.contains( {'', 'template', 'user'}, ns:lower() ) then table.insert( usedTemplateList, name ) elseif ns == ns:upper() then table.insert( usedTemplateList, ns ) -- Probably a magic word end else if name:match( '^%u+$' ) or name == '!' then table.insert( usedTemplateList, name ) -- Probably a magic word else table.insert( usedTemplateList, 'Template:'..name ) end end end end end end requireList = requireList .. dynamicRequirelist:reject( loadDataList ) requireList = requireList:unique() loadDataList = loadDataList .. dynamicLoadDataList:reject( requireList ) loadDataList = loadDataList:unique() usedTemplateList = usedTemplateList:unique() extraCategories = extraCategories:unique() table.sort( requireList ) table.sort( loadDataList ) table.sort( usedTemplateList ) table.sort( extraCategories ) return requireList, loadDataList, usedTemplateList, extraCategories end --- Returns a list with module and function names used in all '{{#Invoke:moduleName|funcName}}' found on page 'templateName'. ---@param templateName string ---@return table<string, string>[] local function getInvokeCallList( templateName ) local content = mw.title.new( templateName ):getContent() local invokeList = {} assert( content ~= nil, string.format( '%s does not exist', templateName ) ) for moduleName, funcName in string.gmatch( content, '{{[{|safeubt:}]-#[Ii]nvoke:([^|]+)|([^}|]+)[^}]*}}' ) do moduleName = formatModuleName( moduleName ) funcName = mw.text.trim( funcName ) if string.find( funcName, '^{{{' ) then funcName = funcName .. '}}}' end table.insert( invokeList, {moduleName=moduleName, funcName=funcName} ) end invokeList = arr.unique( invokeList, function(x) return x.moduleName..x.funcName end ) table.sort( invokeList, function(x, y) return x.moduleName..x.funcName < y.moduleName..y.funcName end ) return invokeList end ---@param pageName string ---@param addCategories boolean ---@return string local function messageBoxUnused( pageName, addCategories ) local mbox = require( 'Module:Mbox' )._mbox local category = addCategories and '[[Category:Unused modules]]' or '' return mbox( 'This module is unused.', string.format( 'This module is neither invoked by a template nor required/loaded by another module. If this is in error, make sure to add <code>{{[[Template:Documentation|Documentation]]}}</code>/<code>{{[[Template:No documentation|No&nbsp;documentation]]}}</code> to the calling template\'s or parent\'s module documentation.', pageName ), { icon = 'WikimediaUI-Alert.svg' } ) .. category end local function collapseList( list, id, listType ) local text = string.format( '%d %s', #list, listType ) local button = '<span>' .. text .. ':</span>&nbsp;' local content = mHatlist.andList( list, false ) return { tostring( button ) .. tostring( content ) } end --- Creates a link to [[Special:Search]] showing all pages found by getDynamicRequireList() in case it found more than MAX_DYNAMIC_REQUIRE_LIST_LENGTH pages. ---@param query string @This will be in a format like 'Module:Wowee/%' or 'Module:Wowee/%/data' ---@return string local function formatDynamicQueryLink( query ) local prefix = query:match( '^([^/]+)' ) local linkText = query:gsub( '%%', '&lt; ... &gt;' ) query = query:gsub( '^Module:', '' ) query = query:gsub( '([^/]+)/?', function ( match ) if match == '%' then return '\\/[^\\/]+' else return '\\/"' .. match .. '"' end end ) query = query:gsub( '^\\/', '' ) query = string.format( 'intitle:/%s%s/i -intitle:/%s\\/""/i -intitle:doc prefix:"%s"', query, query:find( '"$' ) and '' or '""', query, prefix ) return string.format( '<span class="plainlinks">[%s %s]</span>', tostring( mw.uri.fullUrl( 'Special:Search', { search = query } ) ), linkText ) end ---@param templateName string ---@param addCategories boolean ---@param invokeList table<string, string>[] @This is the list returned by getInvokeCallList() ---@return string local function formatInvokeCallList( templateName, addCategories, invokeList ) local category = addCategories and '[[Category:Lua-based templates]]' or '' local res = {} for _, item in ipairs( invokeList ) do local msg = string.format( "'''%s''' invokes function '''%s''' in [[%s]] using [[Star Citizen:Lua|Lua]].", templateName, item.funcName, item.moduleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #invokeList > 0 then table.insert( res, category ) end return table.concat( res ) end ---@param moduleName string ---@param addCategories boolean ---@param whatLinksHere string @A list generated by a dpl of pages in the Template namespace which link to moduleName. ---@return string local function formatInvokedByList( moduleName, addCategories, whatLinksHere ) local function lcfirst( str ) return string.gsub( str, '^[Mm]odule:.', string.lower ) end local templateData = arr.map( whatLinksHere, function(x) return {templateName=x, invokeList=getInvokeCallList(x)} end ) templateData = arr.filter( templateData, function(x) return arr.any( x.invokeList, function(y) return lcfirst(y.moduleName) == lcfirst(moduleName) end ) end ) local invokedByList = {} for _, template in ipairs( templateData ) do for _, invoke in ipairs( template.invokeList ) do table.insert( invokedByList, string.format( "function '''%s''' is invoked by [[%s]]", invoke.funcName, template.templateName ) ) end end table.sort( invokedByList) local res = {} if #invokedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then local msg = string.format( "'''%s''' is invoked by %s.", moduleName, collapseList( invokedByList, 'invokedBy', 'templates' )[1] ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) else for _, item in ipairs( invokedByList ) do local msg = string.format( "'''%s's''' %s.", moduleName, item ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end end if #templateData > 0 then moduleIsUsed = true table.insert( res, (addCategories and '[[Category:Template invoked modules]]' or '') ) end return table.concat( res ) end ---@param moduleName string ---@param addCategories boolean ---@param whatLinksHere string @A list generated by a dpl of pages in the Module namespace which link to moduleName. ---@return string local function formatRequiredByList( moduleName, addCategories, whatLinksHere ) local childModuleData = arr.map( whatLinksHere, function ( title ) local requireList, loadDataList = getRequireList( title ) return {name=title, requireList=requireList, loadDataList=loadDataList} end ) local requiredByList = arr.map( childModuleData, function ( item ) if arr.any( item.requireList, function(x) return x:lower()==moduleName:lower() end ) then if item.name:find( '%%' ) then return formatDynamicQueryLink( item.name ) else return '[[' .. item.name .. ']]' end end end ) local loadedByList = arr.map( childModuleData, function ( item ) if arr.any( item.loadDataList, function(x) return x:lower()==moduleName:lower() end ) then if item.name:find( '%%' ) then return formatDynamicQueryLink( item.name ) else return '[[' .. item.name .. ']]' end end end ) if #requiredByList > 0 or #loadedByList > 0 then moduleIsUsed = true end if #requiredByList > COLLAPSE_LIST_LENGTH_THRESHOLD then requiredByList = collapseList( requiredByList, 'requiredBy', 'modules' ) end if #loadedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then loadedByList = collapseList( loadedByList, 'loadedBy', 'modules' ) end local res = {} for _, requiredByModuleName in ipairs( requiredByList ) do local msg = string.format( "'''%s''' is required by %s.", moduleName, requiredByModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #requiredByList > 0 then table.insert( res, (addCategories and '[[Category:Modules required by modules]]' or '') ) end for _, loadedByModuleName in ipairs( loadedByList ) do local msg = string.format( "'''%s''' is loaded by %s.", moduleName, requiredByModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #loadedByList > 0 then table.insert( res, (addCategories and '[[Category:Module data]]' or '') ) end return table.concat( res ) end local function formatRequireList( currentPageName, addCategories, requireList ) local res = {} if #requireList > COLLAPSE_LIST_LENGTH_THRESHOLD then requireList = collapseList( requireList, 'require', 'modules' ) end for _, requiredModuleName in ipairs( requireList ) do local msg = string.format( "'''%s''' requires %s.", currentPageName, requiredModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #requireList > 0 then table.insert( res, (addCategories and '[[Category:Modules requiring modules]]' or '') ) end return table.concat( res ) end local function formatLoadDataList( currentPageName, addCategories, loadDataList ) local res = {} if #loadDataList > COLLAPSE_LIST_LENGTH_THRESHOLD then loadDataList = collapseList( loadDataList, 'loadData', 'modules' ) end for _, loadedModuleName in ipairs( loadDataList ) do local msg = string.format( "'''%s''' loads data from %s.", currentPageName, loadedModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #loadDataList > 0 then table.insert( res, (addCategories and '[[Category:Modules using data]]' or '') ) end return table.concat( res ) end local function formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList ) local res = {} if #usedTemplateList > COLLAPSE_LIST_LENGTH_THRESHOLD then usedTemplateList = collapseList( usedTemplateList, 'usedTemplates', 'templates' ) end for _, templateName in ipairs( usedTemplateList ) do local msg = string.format( "'''%s''' transcludes [[%s]] using <samp>frame:preprocess()</samp>.", currentPageName, templateName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end return table.concat( res ) end function p.main( frame ) local args = frame:getParent().args return p._main( args[1], args.category, args.isUsed ) end ---@param currentPageName string|nil ---@param addCategories boolean|string|nil ---@return string function p._main( currentPageName, addCategories, isUsed ) libraryUtil.checkType( 'Module:RequireList._main', 1, currentPageName, 'string', true ) libraryUtil.checkTypeMulti( 'Module:RequireList._main', 2, addCategories, {'boolean', 'string', 'nil'} ) libraryUtil.checkTypeMulti( 'Module:RequireList._main', 3, isUsed, {'boolean', 'string', 'nil'} ) local title = mw.title.getCurrentTitle() -- Leave early if not in module or template namespace if param.is_empty( currentPageName ) and ( not arr.contains( {'Module', 'Template'}, title.nsText ) ) then return '' end currentPageName = param.default_to( currentPageName, title.fullText ) currentPageName = string.gsub( currentPageName, '/[Dd]oc$', '' ) currentPageName = formatPageName( currentPageName ) addCategories = yn( param.default_to( addCategories, title.subpageText~='doc' ) ) moduleIsUsed = yn( param.default_to( isUsed, false ) ) if title.text:lower():find( 'sandbox' ) then moduleIsUsed = true -- Don't show sandbox modules as unused end if currentPageName:find( '^Template:' ) then local ok, invokeList = pcall( getInvokeCallList, currentPageName ) if ok then return formatInvokeCallList( currentPageName, addCategories, invokeList ) else return userError(invokeList) end end local whatTemplatesLinkHere, whatModulesLinkHere = dpl.ask( { namespace = 'Template', linksto = currentPageName, distinct = 'strict', ignorecase = true, ordermethod = 'title', allowcachedresults = true, cacheperiod = 604800 -- One week }, { namespace = 'Module', linksto = currentPageName, nottitlematch = '%/doc%|' .. currentPageName:gsub( 'Module:', '' ), distinct = 'strict', ignorecase = true, ordermethod = 'title', allowcachedresults = true, cacheperiod = 604800 -- One week } ) local requireList, loadDataList, usedTemplateList, extraCategories; do local ok; ok, requireList, loadDataList, usedTemplateList, extraCategories = pcall(getRequireList, currentPageName, true); if not ok then return userError(requireList); end end requireList = arr.map( requireList, function ( moduleName ) if moduleName:find( '%%' ) then return formatDynamicQueryLink( moduleName ) else return '[[' .. moduleName .. ']]' end end ) loadDataList = arr.map( loadDataList, function ( moduleName ) if moduleName:find( '%%' ) then return formatDynamicQueryLink( moduleName ) else return '[[' .. moduleName .. ']]' end end ) usedTemplateList = arr.map( usedTemplateList, function( templateName ) if string.find( templateName, ':' ) then -- Real templates are prefixed by a namespace, magic words are not return '[['..templateName..']]' else return "'''&#123;&#123;"..templateName.."&#125;&#125;'''" -- Magic words don't have a page so make them bold instead end end ) local res = {} table.insert( res, formatInvokedByList( currentPageName, addCategories, whatTemplatesLinkHere ) ) table.insert( res, formatRequireList( currentPageName, addCategories, requireList ) ) table.insert( res, formatLoadDataList( currentPageName, addCategories, loadDataList ) ) table.insert( res, formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList ) ) table.insert( res, formatRequiredByList( currentPageName, addCategories, whatModulesLinkHere ) ) if addCategories then extraCategories = arr.map(extraCategories, function(categoryName) return "[[Category:" .. categoryName .. "]]"; end); table.insert(res, table.concat(extraCategories)); end if not moduleIsUsed then table.insert( res, 1, messageBoxUnused( currentPageName:gsub( 'Module:', '' ), addCategories ) ) end return table.concat( res ) end return p -- </nowiki> d5f03ab1075172cdbb69e217ef5ed86f0d973480 Module:Infobox/styles.css 828 64 126 2023-07-15T08:05:29Z star>Alistair3149 0 text text/plain .infobox { /* In case if tooltips go out of boundary */ overflow: visible; width: 100%; max-width: 400px; margin-top: 0; margin-bottom: var( --space-md ); background: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); border-spacing: 0; font-size: 0.875rem; text-align: left; display: block; } /* Table elements */ .infobox tbody { display: flex; flex-wrap: wrap; } .infobox tr { display: flex; box-sizing: border-box; flex-direction: column; padding: 0 10px; margin-top: 10px; } .infobox th, .infobox td { padding: 0 5px; } /* Infobox column */ .infobox .infobox-nocol { width: 100%; flex-direction: row; } .infobox .infobox-nocol th { width: 30%; } .infobox .infobox-nocol td { width: 70%; } .infobox .infobox-col1 { width: 100%; } .infobox .infobox-col2 { width: 50%; } .infobox .infobox-col3 { width: calc( 100% / 3 ); } .infobox .infobox-col4 { width: 25%; } .infobox-data { min-width: 25%; } /* Infobox image */ .infobox .infobox-image { overflow: hidden; padding: 0; margin-top: 0; border-radius: var( --border-radius--medium ) var( --border-radius--medium ) 0 0; } .infobox-image td { padding: 0; } .infobox-image--light .image { background: #eaecf0; } .infobox-image--dark .image { background: #2b2f36; } .infobox-image .image:hover img { transform: scale( 1.1 ); } .infobox-image img { display: block; max-width: 100%; background: var( --background-color-quiet--hover ); } /* Neutral background for all transprent SVG */ .infobox-image img[ src$='.svg' ] { background: #eaecf0; } /* Infobox title */ .infobox .infobox-title { width: 100%; margin-top: 20px; margin-bottom: 5px; color: var( --color-base--emphasized ); font-size: var( --font-size-h3 ); line-height: var( --line-height-xs ); } /* Infobox indicator */ .infobox .infobox-indicator { margin-top: 0; padding: 0; } /* Infobox subtitle */ .infobox .infobox-subtitle { /* Cancel infobox-title bottom margin */ margin-top: -5px; margin-bottom: 5px; } .infobox .infobox-indicator th, .infobox .infobox-subtitle th { display: none; } /* Infobox header */ .infobox .infobox-header { width: 100%; padding-top: 15px; border-top: 1px solid; border-color: var( --border-color-base ); margin-top: 15px; color: var( --color-base--emphasized ); line-height: var( --line-height-xs ); font-size: 1rem; } /* Infobox value */ .infobox-data th { color: var( --color-base--subtle ); font-size: 0.8125rem; font-weight: normal; letter-spacing: 0.75px; } .infobox-data td { font-weight: 600; } .infobox-data ul, .infobox-data ol { margin-top: 0; } /* Infobox button */ .infobox .infobox-button-bar { width: 100%; padding: 0; margin-top: 25px; text-align: center; } .infobox-button-bar th { padding: 0; } /* Collapsible toggle */ .infobox tr:first-of-type .mw-collapsible-toggle { position: relative; display: none; float: none; } .infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text { position: absolute; right: 0; display: block; padding: 5px 15px; background: var( --color-destructive ); border-radius: 0 var( --border-radius--medium ); color: #fff; } .infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:hover { background: var( --color-destructive--hover ); } .infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:active { background: var( --color-destructive--active ); } .infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text { background: var( --color-primary ); } .infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:hover { background: var( --color-primary--hover ); } .infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:active { background: var( --color-primary--active ); } .infobox tr:first-of-type .mw-collapsible-toggle:before, .infobox tr:first-of-type .mw-collapsible-toggle:after { content: none; } @media only screen and ( max-width: 720px ) { .infobox { margin-right: auto; margin-left: auto; } .infobox tr:first-of-type .mw-collapsible-toggle { display: block; } } 754ac9608eeaef9b15784d251643ea8c0a01b58e Module:Documentation 828 56 110 2023-11-10T05:31:21Z star>Alistair3149 0 Undo revision 230589 by [[Special:Contributions/Alistair3149|Alistair3149]] ([[User talk:Alistair3149|talk]]) Scribunto text/plain -- <nowiki> local dependencyList = require( 'Module:DependencyList' ) local yn = require( 'Module:Yesno' ) local hatnote = require( 'Module:Hatnote' )._hatnote local mbox = require( 'Module:Mbox' )._mbox local lang = mw.getContentLanguage() local p = {} function p.doc( frame ) local title = mw.title.getCurrentTitle() local args = frame:getParent().args local page = args[1] or mw.ustring.gsub( title.fullText, '/doc$', '' ) local ret, cats, ret1, ret2, ret3 local pageType = title.namespace == 828 and 'module' or 'template' local opts = frame.args; -- subpage header if title.subpageText == 'doc' then ret = mbox( 'This is a documentation subpage for ' .. page .. '.', string.format( 'It contains usage information, categories, and other content that is not part of the [[' .. page .. '|original %s page]].', pageType ), { icon = 'WikimediaUI-Notice.svg' } ) if title.namespace == 10 then -- Template namespace cats = '[[Category:Template documentation|' .. title.baseText .. ']]' ret2 = dependencyList._main() elseif title.namespace == 828 then -- Module namespace cats = '[[Category:Module documentation|' .. title.baseText .. ']]' ret2 = dependencyList._main() ret2 = ret2 .. require('Module:Module toc').main() else cats = '' ret2 = '' end return tostring( ret ) .. ret2 .. cats end -- template header -- don't use mw.html as we aren't closing the main div tag ret1 = '<div class="documentation">' ret2 = mw.html.create( nil ) :tag( 'div' ) :addClass( 'documentation-header' ) :tag( 'span' ) :addClass( 'documentation-title' ) :wikitext( lang:ucfirst( string.format('%s documentation', pageType) ) ) :done() :tag( 'span' ) :addClass( 'documentation-links plainlinks' ) :wikitext( '[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='view'} ) ) .. ' view]]' .. '[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='edit'} ) ) .. ' edit]]' .. '[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='history'} ) ) .. ' history]]' .. '[<span class="jsPurgeLink">[' .. tostring( mw.uri.fullUrl( title.fullText, {action='purge'} ) ) .. ' purge]</span>]' ) :done() :done() :tag( 'div' ) :addClass( 'documentation-subheader' ) :tag( 'span' ) :addClass( 'documentation-documentation' ) :wikitext( 'This documentation is transcluded from [[' .. page .. '/doc]]. Changes can be proposed in the talk page.' ) :done() :wikitext(frame:extensionTag{ name = 'templatestyles', args = { src = 'Documentation/styles.css'} }) :done() ret3 = {} if args.scwShared then --- Message box table.insert( ret3, mbox( string.format( "'''%s''' is [%s%s shared across] the Star Citizen Wikis.", title.fullText, 'https://github.com/The-Star-Citizen-Wikis/SharedModules/tree/master/', mw.uri.encode( title.rootText, 'PATH' ) ), string.format( 'This %s is shared across the Star Citizen Wikis. Any changes should also be relayed to the GitHub repository.', pageType ), { icon = 'WikimediaUI-ArticleDisambiguation-ltr.svg' } ) ) --- Set category table.insert( ret3, string.format( '[[Category:%s shared by the Star Citizen Wikis]]', lang:ucfirst( pageType ) .. 's' ) ) --- Interlanguage link --- TODO: Make this into a for loop when there are more wikis table.insert( ret3, string.format( '[[%s:%s]]', 'de', title.fullText ) ) end if args.fromWikipedia then table.insert( ret3, mbox( string.format( "'''%s''' is imported from [https://en.wikipedia.org/wiki/%s %s] on Wikipedia.", title.fullText, page, page ), string.format( 'This %s is imported from the English Wikipedia. Although the visual appearance might be different, the functionality is identical. Please refer to the Wikipedia page for detailed documentation.', pageType ), { icon = 'WikimediaUI-Logo-Wikipedia.svg' } ) ) --- Set category table.insert( ret3, string.format( '[[Category:%s imported from Wikipedia]]', lang:ucfirst( pageType ) .. 's' ) ) end if title.namespace == 828 then -- Has config if mw.title.new( title.fullText .. '/config.json', 'Module' ).exists then table.insert( ret3, mbox( string.format( "'''%s''' loads configuration from [[%s/config.json]].", title.fullText, title.fullText ), 'This module can be configurated from the config.json subpage.', { icon='WikimediaUI-Settings.svg' } ) ) end -- Has localization if mw.title.new( title.fullText .. '/i18n.json', 'Module' ).exists then table.insert( ret3, mbox( string.format( "'''%s''' loads messages from [[%s/i18n.json]].", title.fullText, title.fullText ), 'This module is designed to be language-neutral. All of the messages are saved in the i18n.json subpage.', { icon='WikimediaUI-Language.svg' } ) ) end -- Testcase page if title.subpageText == 'testcases' then table.insert( ret3, hatnote( string.format( 'This is the test cases page for the module [[Module:%s]].', title.baseText ), { icon='WikimediaUI-LabFlask.svg' } ) ) end end --- Dependency list table.insert( ret3, dependencyList._main( nil, args.category, args.isUsed ) ) -- Has templatestyles if mw.title.new( title.fullText .. '/styles.css' ).exists then table.insert( ret3, hatnote( string.format( "'''%s''' loads styles from [[%s/styles.css]].", title.fullText, title.fullText ), { icon='WikimediaUI-Palette.svg' } ) ) end --- Module stats bar if title.namespace == 828 then table.insert( ret3, '<div class="documentation-modulestats">' ) -- Function list table.insert( ret3, require( 'Module:Module toc' ).main() ) -- Unit tests local testcaseTitle = title.baseText .. '/testcases' if mw.title.new( testcaseTitle, 'Module' ).exists then -- There is probably a better way :P table.insert( ret3, frame:preprocess( '{{#invoke:' .. testcaseTitle .. '|run}}' ) ) end table.insert( ret3, '</div>' ) end return ret1 .. tostring( ret2 ) .. '<div class="documentation-content">' .. table.concat( ret3 ) end return p -- </nowiki> 5a5b6781058f69e3613197f6be6173d07d2bf085 Main Page 0 1 1 2024-01-11T00:17:07Z MediaWiki default 1 Welcome to Miraheze! wikitext text/x-wiki __NOTOC__ == Welcome to {{SITENAME}}! == This Main Page was created automatically and it seems it hasn't been replaced yet. === For the bureaucrat(s) of this wiki === Hello, and welcome to your new wiki! Thank you for choosing Miraheze for the hosting of your wiki, we hope you will enjoy our hosting. You can immediately start working on your wiki or whenever you want. Need help? No problem! We will help you with your wiki as needed. To start, try checking out these helpful links: * [[mw:Special:MyLanguage/Help:Contents|MediaWiki guide]] (e.g. navigation, editing, deleting pages, blocking users) * [[meta:Special:MyLanguage/FAQ|Miraheze FAQ]] * [[meta:Special:MyLanguage/Request features|Request settings changes on your wiki]]. (Extensions, Skin and Logo/Favicon changes should be done through [[Special:ManageWiki]] on your wiki, see [[meta:Special:MyLanguage/ManageWiki|ManageWiki]] for more information.) ==== I still don't understand X! ==== Well, that's no problem. Even if something isn't explained in the documentation/FAQ, we are still happy to help you. You can find us here: * [[meta:Special:MyLanguage/Help center|On our own Miraheze wiki]] * On [[phab:|Phabricator]] * On [https://miraheze.org/discord Discord] * On IRC in #miraheze on irc.libera.chat ([irc://irc.libera.chat/%23miraheze direct link]; [https://web.libera.chat/?channel=#miraheze webchat]) === For visitors of this wiki === Hello, the default Main Page of this wiki (this page) has not yet been replaced by the bureaucrat(s) of this wiki. The bureaucrat(s) might still be working on a Main Page, so please check again later! 21236ac3f8d65e5563b6da6b70815ca6bf1e6616 Template:Day 10 2 3 2 2024-01-11T08:30:40Z EvaTheServal 2 1 revision imported wikitext text/x-wiki <includeonly>'''{{{1|{{FULLPAGENAME}}}}}''' is the {{#switch:{{#time:z|{{{1|{{PAGENAME}}}}}}} |0=first |1=second |2=third |3=fourth |4=fifth |5=sixth |6=seventh |7=eighth |8=ninth |{{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}+1}}}} }} day of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3 | |&#32;({{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}+1}}}} in leap years) }} in the Gregorian calendar.{{#switch:{{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}} |0= |1=&#32;One day remains until the end of the year. |2=&#32;Two days remain until the end of the year. |3=&#32;Three days remain until the end of the year. |4=&#32;Four days remain until the end of the year. |5=&#32;Five days remain until the end of the year. |6=&#32;Six days remain until the end of the year. |7=&#32;Seven days remain until the end of the year. |8=&#32;Eight days remain until the end of the year. |9=&#32;Nine days remain until the end of the year. |&#32; {{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}} days remain until the end of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3 |&#32;({{#expr:365-{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}}} in leap years) | }}. }}</includeonly><noinclude>{{/doc}}</noinclude> 530dc54fd9473a69e2d1ff775d7d2b2a6c206768 Category:Alien language templates 14 3 5 4 2024-01-11T08:30:41Z EvaTheServal 2 1 revision imported wikitext text/x-wiki This category contains templates related displaying alien languages in article. [[Category:Templates]] 31028d351947fb2c12f3d3976ef9be10d8ccdd76 Category:Article management templates 14 4 7 6 2024-01-11T08:30:41Z EvaTheServal 2 1 revision imported wikitext text/x-wiki A list of article management templates [[Category:Templates]] 11b8b439968d60cbb1df76388c0e1e9b122ad13c Category:Audio templates 14 5 9 8 2024-01-11T08:30:42Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Citation templates 14 7 13 12 2024-01-11T08:30:42Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:DPL templates 14 8 15 14 2024-01-11T08:30:43Z EvaTheServal 2 1 revision imported wikitext text/x-wiki This category contains templates which are designed solely for use with [https://help.gamepedia.com/Extension:DPL3/Manual DynamicPageList3]. For all page that uses DPL calls, see [[Special:WhatLinksHere/Template:Extension DPL]]. [[Category:Templates]] 2bb614cfa9d61ac951d5b671ebaa9bfbbd6fed0c Category:External link templates 14 9 17 16 2024-01-11T08:30:43Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:File management templates 14 10 19 18 2024-01-11T08:30:43Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Formatting and function templates 14 11 21 20 2024-01-11T08:30:44Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:General wiki templates 14 12 23 22 2024-01-11T08:30:44Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Graph, chart, and plot templates 14 13 25 24 2024-01-11T08:30:45Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|used to produce graphs}} [[Category:Templates]] d2eb48d7551d51c120fdbfa06a3981e0053afb31 Category:I18n templates 14 14 27 26 2024-01-11T08:30:45Z EvaTheServal 2 1 revision imported wikitext text/x-wiki '''I18n templates''' are templates contain repetitive words used in the whole wiki. The following templates help to reduce redundancy in translations and also serve as the standard translation for frequently used words. [[Category:Templates]] 7717381b16fc84d004cf6f5bdaa73fa9febd0b07 Category:Infobox Templates 14 15 29 28 2024-01-11T08:30:46Z EvaTheServal 2 1 revision imported wikitext text/x-wiki See [[Help:Infoboxes]] [[Category:Templates]] 50fb8af8e4d62b8e888bb9246e15a1806c52b2b5 Category:Infobox templates 14 16 31 30 2024-01-11T08:30:46Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Interface message templates 14 17 33 32 2024-01-11T08:30:47Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|MediaWiki interface messages}} [[Category:Templates]] 2ceb3a9c4b6b1e027d79edc01030738d73250add Category:Internal link templates 14 18 35 34 2024-01-11T08:30:47Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Language templates 14 19 37 36 2024-01-11T08:30:48Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Lua-based templates 14 20 39 38 2024-01-11T08:30:48Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Main page templates 14 21 41 40 2024-01-11T08:30:49Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|used on the main page}} [[Category:Templates]] fe5a1f6fb0db7ec3bd95014a7935715fb7558c94 Category:Maintenance templates 14 22 43 42 2024-01-11T08:30:49Z EvaTheServal 2 1 revision imported wikitext text/x-wiki This category contains templates related to ones that are used in articles that require maintenance. [[Category:Templates]] 258ee9e751f38daed5ebb5a2281fa0f03311d340 Category:Manual templates 14 23 45 44 2024-01-11T08:30:50Z EvaTheServal 2 1 revision imported wikitext text/x-wiki Below are WIP templates that require manual update frequently as of now, and they are pending to be automated in the future. [[Category:Templates]] 6b82ad760e14f78fdd70dc3f3d47ab254e57ff36 Category:Mathematical function templates 14 24 47 46 2024-01-11T08:30:50Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Navplates 14 25 49 48 2024-01-11T08:30:51Z EvaTheServal 2 1 revision imported wikitext text/x-wiki '''Navplates''' are navigation components that help visitor to visit pages that fall under the same category. [[Category:Templates]] ffa7595179dc81205203c976231a54a062e09851 Category:Number templates 14 26 51 50 2024-01-11T08:30:51Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|manipulate number string}} [[Category:Templates]] 8767a5b6f92ac0662e9e3feae33c87ecc776d542 Category:Numerical conversion templates 14 27 53 52 2024-01-11T08:30:51Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|convert numbers}} [[Category:Templates]] 8d11e0ccdfed85c0343603873eb362298ca75a25 Category:Preload text templates 14 28 55 54 2024-01-11T08:30:52Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|used for article creation}} [[Category:Templates]] 21360b4c5b0d6bef10209484084e8beb67641662 Category:SEO templates 14 29 57 56 2024-01-11T08:30:52Z EvaTheServal 2 1 revision imported wikitext text/x-wiki One of these templates should be included in all page in the main namespace [[Category:Templates]] 0a8943c2a2dbff16b4685086e66c2086c7d39367 Category:String manipulation templates 14 31 61 60 2024-01-11T08:30:53Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Substitution only templates 14 32 63 62 2024-01-11T08:30:53Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Templates imported from Wikipedia 14 33 65 64 2024-01-11T08:30:53Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Templates using TemplateStyles 14 34 67 66 2024-01-11T08:30:54Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|using [[Star Citizen:TemplateStyles|TemplateStyles]]}} [[Category:Templates]] 7281aa1e395de9d8c368a3975548ace744177ec3 Category:Typing-aid templates 14 35 69 68 2024-01-11T08:30:55Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Under-construction templates 14 36 71 70 2024-01-11T08:30:55Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Utility templates 14 37 73 72 2024-01-11T08:30:55Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Category header|templates|that are not suitable to use directly on pages. They should only be used in templates|related=no}} [[Category:Templates]] 8ef6eadc680eea4f36a48b5fbf988cab1768b2ef Category:Vehicle Specification Templates 14 38 75 74 2024-01-11T08:30:56Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Category:Vehicle specification templates 14 39 77 76 2024-01-11T08:30:56Z EvaTheServal 2 1 revision imported wikitext text/x-wiki [[Category:Templates]] 06eecdec29f6cb215c99cf216d1e3bdc8c30a95e Module:Arguments 828 40 79 78 2024-01-11T08:30:57Z EvaTheServal 2 1 revision imported Scribunto text/plain -- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly. local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local arguments = {} -- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it. local function tidyValDefault(key, val) if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val == '' then return nil else return val end else return val end end local function tidyValTrimOnly(key, val) if type(val) == 'string' then return val:match('^%s*(.-)%s*$') else return val end end local function tidyValRemoveBlanksOnly(key, val) if type(val) == 'string' then if val:find('%S') then return val else return nil end else return val end end local function tidyValNoChange(key, val) return val end local function matchesTitle(given, title) local tp = type( given ) return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title end local translate_mt = { __index = function(t, k) return k end } function arguments.getArgs(frame, options) checkType('getArgs', 1, frame, 'table', true) checkType('getArgs', 2, options, 'table', true) frame = frame or {} options = options or {} --[[ -- Set up argument translation. --]] options.translate = options.translate or {} if getmetatable(options.translate) == nil then setmetatable(options.translate, translate_mt) end if options.backtranslate == nil then options.backtranslate = {} for k,v in pairs(options.translate) do options.backtranslate[v] = k end end if options.backtranslate and getmetatable(options.backtranslate) == nil then setmetatable(options.backtranslate, { __index = function(t, k) if options.translate[k] ~= k then return nil else return k end end }) end --[[ -- Get the argument tables. If we were passed a valid frame object, get the -- frame arguments (fargs) and the parent frame arguments (pargs), depending -- on the options set and on the parent frame's availability. If we weren't -- passed a valid frame object, we are being called from another Lua module -- or from the debug console, so assume that we were passed a table of args -- directly, and assign it to a new variable (luaArgs). --]] local fargs, pargs, luaArgs if type(frame.args) == 'table' and type(frame.getParent) == 'function' then if options.wrappers then --[[ -- The wrappers option makes Module:Arguments look up arguments in -- either the frame argument table or the parent argument table, but -- not both. This means that users can use either the #invoke syntax -- or a wrapper template without the loss of performance associated -- with looking arguments up in both the frame and the parent frame. -- Module:Arguments will look up arguments in the parent frame -- if it finds the parent frame's title in options.wrapper; -- otherwise it will look up arguments in the frame object passed -- to getArgs. --]] local parent = frame:getParent() if not parent then fargs = frame.args else local title = parent:getTitle():gsub('/sandbox$', '') local found = false if matchesTitle(options.wrappers, title) then found = true elseif type(options.wrappers) == 'table' then for _,v in pairs(options.wrappers) do if matchesTitle(v, title) then found = true break end end end -- We test for false specifically here so that nil (the default) acts like true. if found or options.frameOnly == false then pargs = parent.args end if not found or options.parentOnly == false then fargs = frame.args end end else -- options.wrapper isn't set, so check the other options. if not options.parentOnly then fargs = frame.args end if not options.frameOnly then local parent = frame:getParent() pargs = parent and parent.args or nil end end if options.parentFirst then fargs, pargs = pargs, fargs end else luaArgs = frame end -- Set the order of precedence of the argument tables. If the variables are -- nil, nothing will be added to the table, which is how we avoid clashes -- between the frame/parent args and the Lua args. local argTables = {fargs} argTables[#argTables + 1] = pargs argTables[#argTables + 1] = luaArgs --[[ -- Generate the tidyVal function. If it has been specified by the user, we -- use that; if not, we choose one of four functions depending on the -- options chosen. This is so that we don't have to call the options table -- every time the function is called. --]] local tidyVal = options.valueFunc if tidyVal then if type(tidyVal) ~= 'function' then error( "bad value assigned to option 'valueFunc'" .. '(function expected, got ' .. type(tidyVal) .. ')', 2 ) end elseif options.trim ~= false then if options.removeBlanks ~= false then tidyVal = tidyValDefault else tidyVal = tidyValTrimOnly end else if options.removeBlanks ~= false then tidyVal = tidyValRemoveBlanksOnly else tidyVal = tidyValNoChange end end --[[ -- Set up the args, metaArgs and nilArgs tables. args will be the one -- accessed from functions, and metaArgs will hold the actual arguments. Nil -- arguments are memoized in nilArgs, and the metatable connects all of them -- together. --]] local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} setmetatable(args, metatable) local function mergeArgs(tables) --[[ -- Accepts multiple tables as input and merges their keys and values -- into one table. If a value is already present it is not overwritten; -- tables listed earlier have precedence. We are also memoizing nil -- values, which can be overwritten if they are 's' (soft). --]] for _, t in ipairs(tables) do for key, val in pairs(t) do if metaArgs[key] == nil and nilArgs[key] ~= 'h' then local tidiedVal = tidyVal(key, val) if tidiedVal == nil then nilArgs[key] = 's' else metaArgs[key] = tidiedVal end end end end end --[[ -- Define metatable behaviour. Arguments are memoized in the metaArgs table, -- and are only fetched from the argument tables once. Fetching arguments -- from the argument tables is the most resource-intensive step in this -- module, so we try and avoid it where possible. For this reason, nil -- arguments are also memoized, in the nilArgs table. Also, we keep a record -- in the metatable of when pairs and ipairs have been called, so we do not -- run pairs and ipairs on the argument tables more than once. We also do -- not run ipairs on fargs and pargs if pairs has already been run, as all -- the arguments will already have been copied over. --]] metatable.__index = function (t, key) --[[ -- Fetches an argument when the args table is indexed. First we check -- to see if the value is memoized, and if not we try and fetch it from -- the argument tables. When we check memoization, we need to check -- metaArgs before nilArgs, as both can be non-nil at the same time. -- If the argument is not present in metaArgs, we also check whether -- pairs has been run yet. If pairs has already been run, we return nil. -- This is because all the arguments will have already been copied into -- metaArgs by the mergeArgs function, meaning that any other arguments -- must be nil. --]] if type(key) == 'string' then key = options.translate[key] end local val = metaArgs[key] if val ~= nil then return val elseif metatable.donePairs or nilArgs[key] then return nil end for _, argTable in ipairs(argTables) do local argTableVal = tidyVal(key, argTable[key]) if argTableVal ~= nil then metaArgs[key] = argTableVal return argTableVal end end nilArgs[key] = 'h' return nil end metatable.__newindex = function (t, key, val) -- This function is called when a module tries to add a new value to the -- args table, or tries to change an existing value. if type(key) == 'string' then key = options.translate[key] end if options.readOnly then error( 'could not write to argument table key "' .. tostring(key) .. '"; the table is read-only', 2 ) elseif options.noOverwrite and args[key] ~= nil then error( 'could not write to argument table key "' .. tostring(key) .. '"; overwriting existing arguments is not permitted', 2 ) elseif val == nil then --[[ -- If the argument is to be overwritten with nil, we need to erase -- the value in metaArgs, so that __index, __pairs and __ipairs do -- not use a previous existing value, if present; and we also need -- to memoize the nil in nilArgs, so that the value isn't looked -- up in the argument tables if it is accessed again. --]] metaArgs[key] = nil nilArgs[key] = 'h' else metaArgs[key] = val end end local function translatenext(invariant) local k, v = next(invariant.t, invariant.k) invariant.k = k if k == nil then return nil elseif type(k) ~= 'string' or not options.backtranslate then return k, v else local backtranslate = options.backtranslate[k] if backtranslate == nil then -- Skip this one. This is a tail call, so this won't cause stack overflow return translatenext(invariant) else return backtranslate, v end end end metatable.__pairs = function () -- Called when pairs is run on the args table. if not metatable.donePairs then mergeArgs(argTables) metatable.donePairs = true end return translatenext, { t = metaArgs } end local function inext(t, i) -- This uses our __index metamethod local v = t[i + 1] if v ~= nil then return i + 1, v end end metatable.__ipairs = function (t) -- Called when ipairs is run on the args table. return inext, t, 0 end return args end return arguments 3134ecce8429b810d445e29eae115e2ae4c36c53 Module:Hatnote 828 41 81 80 2024-01-11T08:30:59Z EvaTheServal 2 1 revision imported Scribunto text/plain -------------------------------------------------------------------------------- -- Module:Hatnote -- -- -- -- This module produces hatnote links and links to related articles. It -- -- implements the {{hatnote}} and {{format link}} meta-templates and includes -- -- helper functions for other Lua hatnote modules. -- -------------------------------------------------------------------------------- local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local mArguments -- lazily initialise [[Module:Arguments]] local yesno -- lazily initialise [[Module:Yesno]] local p = {} -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function getArgs(frame) -- Fetches the arguments from the parent frame. Whitespace is trimmed and -- blanks are removed. mArguments = require('Module:Arguments') return mArguments.getArgs(frame, {parentOnly = true}) end local function removeInitialColon(s) -- Removes the initial colon from a string, if present. return s:match('^:?(.*)') end function p.defaultClasses(inline) -- Provides the default hatnote classes as a space-separated string; useful -- for hatnote-manipulation modules like [[Module:Hatnote group]]. return (inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' .. 'navigation-not-searchable' end function p.disambiguate(page, disambiguator) -- Formats a page title with a disambiguation parenthetical, -- i.e. "Example" → "Example (disambiguation)". checkType('disambiguate', 1, page, 'string') checkType('disambiguate', 2, disambiguator, 'string', true) disambiguator = disambiguator or 'disambiguation' return mw.ustring.format('%s (%s)', page, disambiguator) end function p.findNamespaceId(link, removeColon) -- Finds the namespace id (namespace number) of a link or a pagename. This -- function will not work if the link is enclosed in double brackets. Colons -- are trimmed from the start of the link by default. To skip colon -- trimming, set the removeColon parameter to false. checkType('findNamespaceId', 1, link, 'string') checkType('findNamespaceId', 2, removeColon, 'boolean', true) if removeColon ~= false then link = removeInitialColon(link) end local namespace = link:match('^(.-):') if namespace then local nsTable = mw.site.namespaces[namespace] if nsTable then return nsTable.id end end return 0 end function p.makeWikitextError(msg, helpLink, addTrackingCategory, title) -- Formats an error message to be returned to wikitext. If -- addTrackingCategory is not false after being returned from -- [[Module:Yesno]], and if we are not on a talk page, a tracking category -- is added. checkType('makeWikitextError', 1, msg, 'string') checkType('makeWikitextError', 2, helpLink, 'string', true) yesno = require('Module:Yesno') title = title or mw.title.getCurrentTitle() -- Make the help link text. local helpText if helpLink then helpText = ' ([[' .. helpLink .. '|help]])' else helpText = '' end -- Make the category text. local category if not title.isTalkPage -- Don't categorise talk pages and title.namespace ~= 2 -- Don't categorise userspace and yesno(addTrackingCategory) ~= false -- Allow opting out then category = 'Hatnote templates with errors' category = mw.ustring.format( '[[%s:%s]]', mw.site.namespaces[14].name, category ) else category = '' end return mw.ustring.format( '<strong class="error">Error: %s%s.</strong>%s', msg, helpText, category ) end local curNs = mw.title.getCurrentTitle().namespace p.missingTargetCat = --Default missing target category, exported for use in related modules ((curNs == 0) or (curNs == 14)) and 'Articles with hatnote templates targeting a nonexistent page' or nil function p.quote(title) --Wraps titles in quotation marks. If the title starts/ends with a quotation --mark, kerns that side as with {{-'}} local quotationMarks = { ["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true } local quoteLeft, quoteRight = -- Test if start/end are quotation marks quotationMarks[string.sub(title, 1, 1)], quotationMarks[string.sub(title, -1, -1)] if quoteLeft or quoteRight then title = mw.html.create("span"):wikitext(title) end if quoteLeft then title:css("padding-left", "0.15em") end if quoteRight then title:css("padding-right", "0.15em") end return '"' .. tostring(title) .. '"' end -------------------------------------------------------------------------------- -- Hatnote -- -- Produces standard hatnote text. Implements the {{hatnote}} template. -------------------------------------------------------------------------------- local function decorateHatnote(hatnote, options) local function getIcon(filename) local html = '' if type(filename) == 'string' then local icon = mw.html.create('span') icon :addClass('hatnote-icon') :addClass('metadata') :wikitext('[[File:' .. filename .. '|14px|link=]]') :done() html = tostring(icon) end return html end local container = mw.html.create('div') container :addClass('hatnote-container') :wikitext(getIcon(options.icon)) :wikitext(tostring(hatnote)) :done() return container end function p.hatnote(frame) local args = getArgs(frame) local s = args[1] if not s then return p.makeWikitextError( 'no text specified', 'Template:Hatnote#Errors', args.category ) end return p._hatnote(s, { extraclasses = args.extraclasses, selfref = args.selfref }) end function p._hatnote(s, options) checkType('_hatnote', 1, s, 'string') checkType('_hatnote', 2, options, 'table', true) options = options or {} local inline = options.inline local hatnote = mw.html.create(inline == 1 and 'span' or 'div') local extraclasses if type(options.extraclasses) == 'string' then extraclasses = options.extraclasses end hatnote :attr('role', 'note') :addClass(p.defaultClasses(inline)) :addClass(extraclasses) :addClass(options.selfref and 'selfref' or nil) :wikitext(s) -- Decorate WP hatnote to SCW standard hatnote = decorateHatnote(hatnote, options) return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' } } .. tostring(hatnote) end return p 7e322cb6950c0f36959bceccc679cc8f52959f7c Template:Note 10 42 83 82 2024-01-11T08:30:59Z EvaTheServal 2 1 revision imported wikitext text/x-wiki #REDIRECT [[Template:Hatnote]] 9582e82fbead373024765d896e4930eee521d846 Module:String 828 43 85 84 2024-01-11T08:31:00Z EvaTheServal 2 1 revision imported Scribunto text/plain --[[ This module is intended to provide access to basic string functions. Most of the functions provided here can be invoked with named parameters, unnamed parameters, or a mixture. If named parameters are used, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. Depending on the intended use, it may be advantageous to either preserve or remove such whitespace. Global options ignore_errors: If set to 'true' or 1, any error condition will result in an empty string being returned rather than an error message. error_category: If an error occurs, specifies the name of a category to include with the error message. The default category is [Category:Errors reported by Module String]. no_category: If set to 'true' or 1, no category will be added if an error is generated. Unit tests for this module are available at Module:String/tests. ]] local str = {} --[[ len This function returns the length of the target string. Usage: {{#invoke:String|len|target_string|}} OR {{#invoke:String|len|s=target_string}} Parameters s: The string whose length to report If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. ]] function str.len( frame ) local new_args = str._getParameters( frame.args, {'s'} ) local s = new_args['s'] or '' return mw.ustring.len( s ) end --[[ sub This function returns a substring of the target string at specified indices. Usage: {{#invoke:String|sub|target_string|start_index|end_index}} OR {{#invoke:String|sub|s=target_string|i=start_index|j=end_index}} Parameters s: The string to return a subset of i: The fist index of the substring to return, defaults to 1. j: The last index of the string to return, defaults to the last character. The first character of the string is assigned an index of 1. If either i or j is a negative value, it is interpreted the same as selecting a character by counting from the end of the string. Hence, a value of -1 is the same as selecting the last character of the string. If the requested indices are out of range for the given string, an error is reported. ]] function str.sub( frame ) local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } ) local s = new_args['s'] or '' local i = tonumber( new_args['i'] ) or 1 local j = tonumber( new_args['j'] ) or -1 local len = mw.ustring.len( s ) -- Convert negatives for range checking if i < 0 then i = len + i + 1 end if j < 0 then j = len + j + 1 end if i > len or j > len or i < 1 or j < 1 then return str._error( 'String subset index out of range' ) end if j < i then return str._error( 'String subset indices out of order' ) end return mw.ustring.sub( s, i, j ) end --[[ This function implements that features of {{str sub old}} and is kept in order to maintain these older templates. ]] function str.sublength( frame ) local i = tonumber( frame.args.i ) or 0 local len = tonumber( frame.args.len ) return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) ) end --[[ _match This function returns a substring from the source string that matches a specified pattern. It is exported for use in other modules Usage: strmatch = require("Module:String")._match sresult = strmatch( s, pattern, start, match, plain, nomatch ) Parameters s: The string to search pattern: The pattern or string to find within the string start: The index within the source string to start the search. The first character of the string has index 1. Defaults to 1. match: In some cases it may be possible to make multiple matches on a single string. This specifies which match to return, where the first match is match= 1. If a negative number is specified then a match is returned counting from the last match. Hence match = -1 is the same as requesting the last match. Defaults to 1. plain: A flag indicating that the pattern should be understood as plain text. Defaults to false. nomatch: If no match is found, output the "nomatch" value rather than an error. For information on constructing Lua patterns, a form of [regular expression], see: * http://www.lua.org/manual/5.1/manual.html#5.4.1 * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns ]] -- This sub-routine is exported for use in other modules function str._match( s, pattern, start, match_index, plain_flag, nomatch ) if s == '' then return str._error( 'Target string is empty' ) end if pattern == '' then return str._error( 'Pattern string is empty' ) end start = tonumber(start) or 1 if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then return str._error( 'Requested start is out of range' ) end if match_index == 0 then return str._error( 'Match index is out of range' ) end if plain_flag then pattern = str._escapePattern( pattern ) end local result if match_index == 1 then -- Find first match is simple case result = mw.ustring.match( s, pattern, start ) else if start > 1 then s = mw.ustring.sub( s, start ) end local iterator = mw.ustring.gmatch(s, pattern) if match_index > 0 then -- Forward search for w in iterator do match_index = match_index - 1 if match_index == 0 then result = w break end end else -- Reverse search local result_table = {} local count = 1 for w in iterator do result_table[count] = w count = count + 1 end result = result_table[ count + match_index ] end end if result == nil then if nomatch == nil then return str._error( 'Match not found' ) else return nomatch end else return result end end --[[ match This function returns a substring from the source string that matches a specified pattern. Usage: {{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}} OR {{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index |match=match_number|plain=plain_flag|nomatch=nomatch_output}} Parameters s: The string to search pattern: The pattern or string to find within the string start: The index within the source string to start the search. The first character of the string has index 1. Defaults to 1. match: In some cases it may be possible to make multiple matches on a single string. This specifies which match to return, where the first match is match= 1. If a negative number is specified then a match is returned counting from the last match. Hence match = -1 is the same as requesting the last match. Defaults to 1. plain: A flag indicating that the pattern should be understood as plain text. Defaults to false. nomatch: If no match is found, output the "nomatch" value rather than an error. If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from each string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. If the match_number or start_index are out of range for the string being queried, then this function generates an error. An error is also generated if no match is found. If one adds the parameter ignore_errors=true, then the error will be suppressed and an empty string will be returned on any failure. For information on constructing Lua patterns, a form of [regular expression], see: * http://www.lua.org/manual/5.1/manual.html#5.4.1 * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns ]] -- This is the entry point for #invoke:String|match function str.match( frame ) local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} ) local s = new_args['s'] or '' local start = tonumber( new_args['start'] ) or 1 local plain_flag = str._getBoolean( new_args['plain'] or false ) local pattern = new_args['pattern'] or '' local match_index = math.floor( tonumber(new_args['match']) or 1 ) local nomatch = new_args['nomatch'] return str._match( s, pattern, start, match_index, plain_flag, nomatch ) end --[[ pos This function returns a single character from the target string at position pos. Usage: {{#invoke:String|pos|target_string|index_value}} OR {{#invoke:String|pos|target=target_string|pos=index_value}} Parameters target: The string to search pos: The index for the character to return If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. The first character has an index value of 1. If one requests a negative value, this function will select a character by counting backwards from the end of the string. In other words pos = -1 is the same as asking for the last character. A requested value of zero, or a value greater than the length of the string returns an error. ]] function str.pos( frame ) local new_args = str._getParameters( frame.args, {'target', 'pos'} ) local target_str = new_args['target'] or '' local pos = tonumber( new_args['pos'] ) or 0 if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then return str._error( 'String index out of range' ) end return mw.ustring.sub( target_str, pos, pos ) end --[[ str_find This function duplicates the behavior of {{str_find}}, including all of its quirks. This is provided in order to support existing templates, but is NOT RECOMMENDED for new code and templates. New code is recommended to use the "find" function instead. Returns the first index in "source" that is a match to "target". Indexing is 1-based, and the function returns -1 if the "target" string is not present in "source". Important Note: If the "target" string is empty / missing, this function returns a value of "1", which is generally unexpected behavior, and must be accounted for separatetly. ]] function str.str_find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target'} ) local source_str = new_args['source'] or '' local target_str = new_args['target'] or '' if target_str == '' then return 1 end local start = mw.ustring.find( source_str, target_str, 1, true ) if start == nil then start = -1 end return start end --[[ find This function allows one to search for a target string or pattern within another string. Usage: {{#invoke:String|find|source_str|target_string|start_index|plain_flag}} OR {{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}} Parameters source: The string to search target: The string or pattern to find within source start: The index within the source string to start the search, defaults to 1 plain: Boolean flag indicating that target should be understood as plain text and not as a Lua style regular expression, defaults to true If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. This function returns the first index >= "start" where "target" can be found within "source". Indices are 1-based. If "target" is not found, then this function returns 0. If either "source" or "target" are missing / empty, this function also returns 0. This function should be safe for UTF-8 strings. ]] function str.find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } ) local source_str = new_args['source'] or '' local pattern = new_args['target'] or '' local start_pos = tonumber(new_args['start']) or 1 local plain = new_args['plain'] or true if source_str == '' or pattern == '' then return 0 end plain = str._getBoolean( plain ) local start = mw.ustring.find( source_str, pattern, start_pos, plain ) if start == nil then start = 0 end return start end --[[ replace This function allows one to replace a target string or pattern within another string. Usage: {{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}} OR {{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string| count=replacement_count|plain=plain_flag}} Parameters source: The string to search pattern: The string or pattern to find within source replace: The replacement text count: The number of occurences to replace, defaults to all. plain: Boolean flag indicating that pattern should be understood as plain text and not as a Lua style regular expression, defaults to true ]] function str.replace( frame ) local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } ) local source_str = new_args['source'] or '' local pattern = new_args['pattern'] or '' local replace = new_args['replace'] or '' local count = tonumber( new_args['count'] ) local plain = new_args['plain'] or true if source_str == '' or pattern == '' then return source_str end plain = str._getBoolean( plain ) if plain then pattern = str._escapePattern( pattern ) replace = mw.ustring.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences. end local result if count ~= nil then result = mw.ustring.gsub( source_str, pattern, replace, count ) else result = mw.ustring.gsub( source_str, pattern, replace ) end return result end --[[ simple function to pipe string.rep to templates. ]] function str.rep( frame ) local repetitions = tonumber( frame.args[2] ) if not repetitions then return str._error( 'function rep expects a number as second parameter, received "' .. ( frame.args[2] or '' ) .. '"' ) end return string.rep( frame.args[1] or '', repetitions ) end --[[ escapePattern This function escapes special characters from a Lua string pattern. See [1] for details on how patterns work. [1] https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns Usage: {{#invoke:String|escapePattern|pattern_string}} Parameters pattern_string: The pattern string to escape. ]] function str.escapePattern( frame ) local pattern_str = frame.args[1] if not pattern_str then return str._error( 'No pattern string specified' ) end local result = str._escapePattern( pattern_str ) return result end --[[ count This function counts the number of occurrences of one string in another. ]] function str.count(frame) local args = str._getParameters(frame.args, {'source', 'pattern', 'plain'}) local source = args.source or '' local pattern = args.pattern or '' local plain = str._getBoolean(args.plain or true) if plain then pattern = str._escapePattern(pattern) end local _, count = mw.ustring.gsub(source, pattern, '') return count end --[[ endswith This function determines whether a string ends with another string. ]] function str.endswith(frame) local args = str._getParameters(frame.args, {'source', 'pattern'}) local source = args.source or '' local pattern = args.pattern or '' if pattern == '' then -- All strings end with the empty string. return "yes" end if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then return "yes" else return "" end end --[[ join Join all non empty arguments together; the first argument is the separator. Usage: {{#invoke:String|join|sep|one|two|three}} ]] function str.join(frame) local args = {} local sep for _, v in ipairs( frame.args ) do if sep then if v ~= '' then table.insert(args, v) end else sep = v end end return table.concat( args, sep or '' ) end --[[ Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. ]] function str._getParameters( frame_args, arg_list ) local new_args = {} local index = 1 local value for _, arg in ipairs( arg_list ) do value = frame_args[arg] if value == nil then value = frame_args[index] index = index + 1 end new_args[arg] = value end return new_args end --[[ Helper function to handle error messages. ]] function str._error( error_str ) local frame = mw.getCurrentFrame() local error_category = frame.args.error_category or 'Errors reported by Module String' local ignore_errors = frame.args.ignore_errors or false local no_category = frame.args.no_category or false if str._getBoolean(ignore_errors) then return '' end local error_str = '<strong class="error">String Module Error: ' .. error_str .. '</strong>' if error_category ~= '' and not str._getBoolean( no_category ) then error_str = '[[Category:' .. error_category .. ']]' .. error_str end return error_str end --[[ Helper Function to interpret boolean strings ]] function str._getBoolean( boolean_str ) local boolean_value if type( boolean_str ) == 'string' then boolean_str = boolean_str:lower() if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' or boolean_str == '' then boolean_value = false else boolean_value = true end elseif type( boolean_str ) == 'boolean' then boolean_value = boolean_str else error( 'No boolean value found' ) end return boolean_value end --[[ Helper function that escapes all pattern characters so that they will be treated as plain text. ]] function str._escapePattern( pattern_str ) return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" ) end return str 6df794dd52434e0f6a372c9918f5a9dedd15f579 Template:Nbsp 10 44 87 86 2024-01-11T08:31:01Z EvaTheServal 2 1 revision imported wikitext text/x-wiki #REDIRECT [[Template:Spaces]] d55076009c86bad01caacd67c545037409e5e1ee Template:Spaces 10 45 89 88 2024-01-11T08:31:02Z EvaTheServal 2 1 revision imported wikitext text/x-wiki <span class="nowrap">{{#iferror:{{#expr:{{{1|1}}}}} |{{#switch:{{{1}}} |fig=&#8199; |en=&ensp; |em=&emsp; |thin=&thinsp; |hair=&#8202; |&nbsp; }} |{{#invoke:String|rep|{{#switch:{{{2}}} |fig=&#8199; |en=&ensp; |em=&emsp; |thin=&thinsp; |hair=&#8202; |&nbsp; }}|{{{1|1}}}}} }}</span><noinclude> {{/doc}} </noinclude> 17efb36433f45a5c4f23528902387edcf0e174f0 Template:Category header 10 46 91 90 2024-01-11T08:31:02Z EvaTheServal 2 1 revision imported wikitext text/x-wiki <includeonly>{{Note|This category contains {{{1}}}{{#if:{{{2|}}}|{{#ifeq:{{lc:{{{related|}}}}}|no||{{nbsp}}related to}}{{nbsp}}{{{2}}}}}. {{#if:{{{3|}}}|This category is automatically added by {{{4|}}}.}}}}</includeonly><noinclude>{{/doc}}</noinclude> a396b20e4e0c621cc7538e9a0f085cfbbd37a811 Module:Hatnote/styles.css 828 47 93 92 2024-01-11T08:31:03Z EvaTheServal 2 1 revision imported text text/plain .hatnote-container { display: flex; align-items: center; padding: var( --space-sm ) var( --space-md ); margin-top: var( --space-xs ); margin-bottom: var( --space-md ); background: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); color: var( --color-base--subtle ); font-size: 0.875rem; line-height: var( --line-height-xs ); } .hatnote-icon img { width: 14px; height: auto; margin-right: var( --space-xs ); opacity: var( --opacity-icon-base ); } /* Dark theme */ html.skin-citizen-dark .hatnote-icon img { filter: invert( 1 ); } 44850b74680c356f2514e4292d2130fb67f3b46d Template:Hatnote 10 48 95 94 2024-01-11T08:31:03Z EvaTheServal 2 1 revision imported wikitext text/x-wiki <includeonly>{{#invoke:Hatnote|hatnote}}</includeonly><noinclude>{{/doc}}</noinclude> d9029e1bc2de056708cda99e6ce883644c1661e4 Template:Infobox 10 49 97 96 2024-01-11T08:38:08Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{#invoke:Infobox|infobox}}<noinclude> {{/doc}} <!-- Categories go in the /doc subpage, and interwikis go in Wikidata. --> </noinclude> aaadab5f0433ae495a07ed115145bf7ca42d5c10 Module:Hatnote list 828 50 99 98 2024-01-11T08:38:09Z EvaTheServal 2 1 revision imported Scribunto text/plain -------------------------------------------------------------------------------- -- Module:Hatnote list -- -- -- -- This module produces and formats lists for use in hatnotes. In particular, -- -- it implements the for-see list, i.e. lists of "For X, see Y" statements, -- -- as used in {{about}}, {{redirect}}, and their variants. Also introduced -- -- are andList & orList helpers for formatting lists with those conjunctions. -- -------------------------------------------------------------------------------- local mArguments --initialize lazily local mFormatLink = require('Module:Format link') local mHatnote = require('Module:Hatnote') local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local p = {} -------------------------------------------------------------------------------- -- List stringification helper functions -- -- These functions are used for stringifying lists, usually page lists inside -- the "Y" portion of "For X, see Y" for-see items. -------------------------------------------------------------------------------- --default options table used across the list stringification functions local stringifyListDefaultOptions = { conjunction = "and", separator = ",", altSeparator = ";", space = " ", formatted = false } --Searches display text only local function searchDisp(haystack, needle) return string.find( string.sub(haystack, (string.find(haystack, '|') or 0) + 1), needle ) end -- Stringifies a list generically; probably shouldn't be used directly local function stringifyList(list, options) -- Type-checks, defaults, and a shortcut checkType("stringifyList", 1, list, "table") if #list == 0 then return nil end checkType("stringifyList", 2, options, "table", true) options = options or {} for k, v in pairs(stringifyListDefaultOptions) do if options[k] == nil then options[k] = v end end local s = options.space -- Format the list if requested if options.formatted then list = mFormatLink.formatPages( {categorizeMissing = mHatnote.missingTargetCat}, list ) end -- Set the separator; if any item contains it, use the alternate separator local separator = options.separator for k, v in pairs(list) do if searchDisp(v, separator) then separator = options.altSeparator break end end -- Set the conjunction, apply Oxford comma, and force a comma if #1 has "§" local conjunction = s .. options.conjunction .. s if #list == 2 and searchDisp(list[1], "§") or #list > 2 then conjunction = separator .. conjunction end -- Return the formatted string return mw.text.listToText(list, separator .. s, conjunction) end --DRY function function p.conjList (conj, list, fmt) return stringifyList(list, {conjunction = conj, formatted = fmt}) end -- Stringifies lists with "and" or "or" function p.andList (...) return p.conjList("and", ...) end function p.orList (...) return p.conjList("or", ...) end -------------------------------------------------------------------------------- -- For see -- -- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the -- {{about}} and {{redirect}} templates and their variants. -------------------------------------------------------------------------------- --default options table used across the forSee family of functions local forSeeDefaultOptions = { andKeyword = 'and', title = mw.title.getCurrentTitle().text, otherText = 'other uses', forSeeForm = 'For %s, see %s.', } --Collapses duplicate punctuation local function punctuationCollapse (text) local replacements = { ["%.%.$"] = ".", ["%?%.$"] = "?", ["%!%.$"] = "!", ["%.%]%]%.$"] = ".]]", ["%?%]%]%.$"] = "?]]", ["%!%]%]%.$"] = "!]]" } for k, v in pairs(replacements) do text = string.gsub(text, k, v) end return text end -- Structures arguments into a table for stringification, & options function p.forSeeArgsToTable (args, from, options) -- Type-checks and defaults checkType("forSeeArgsToTable", 1, args, 'table') checkType("forSeeArgsToTable", 2, from, 'number', true) from = from or 1 checkType("forSeeArgsToTable", 3, options, 'table', true) options = options or {} for k, v in pairs(forSeeDefaultOptions) do if options[k] == nil then options[k] = v end end -- maxArg's gotten manually because getArgs() and table.maxn aren't friends local maxArg = 0 for k, v in pairs(args) do if type(k) == 'number' and k > maxArg then maxArg = k end end -- Structure the data out from the parameter list: -- * forTable is the wrapper table, with forRow rows -- * Rows are tables of a "use" string & a "pages" table of pagename strings -- * Blanks are left empty for defaulting elsewhere, but can terminate list local forTable = {} local i = from local terminated = false -- If there is extra text, and no arguments are given, give nil value -- to not produce default of "For other uses, see foo (disambiguation)" if options.extratext and i > maxArg then return nil end -- Loop to generate rows repeat -- New empty row local forRow = {} -- On blank use, assume list's ended & break at end of this loop forRow.use = args[i] if not args[i] then terminated = true end -- New empty list of pages forRow.pages = {} -- Insert first pages item if present table.insert(forRow.pages, args[i + 1]) -- If the param after next is "and", do inner loop to collect params -- until the "and"'s stop. Blanks are ignored: "1|and||and|3" → {1, 3} while args[i + 2] == options.andKeyword do if args[i + 3] then table.insert(forRow.pages, args[i + 3]) end -- Increment to next "and" i = i + 2 end -- Increment to next use i = i + 2 -- Append the row table.insert(forTable, forRow) until terminated or i > maxArg return forTable end -- Stringifies a table as formatted by forSeeArgsToTable function p.forSeeTableToString (forSeeTable, options) -- Type-checks and defaults checkType("forSeeTableToString", 1, forSeeTable, "table", true) checkType("forSeeTableToString", 2, options, "table", true) options = options or {} for k, v in pairs(forSeeDefaultOptions) do if options[k] == nil then options[k] = v end end -- Stringify each for-see item into a list local strList = {} if forSeeTable then for k, v in pairs(forSeeTable) do local useStr = v.use or options.otherText local pagesStr = p.andList(v.pages, true) or mFormatLink._formatLink{ categorizeMissing = mHatnote.missingTargetCat, link = mHatnote.disambiguate(options.title) } local forSeeStr = string.format(options.forSeeForm, useStr, pagesStr) forSeeStr = punctuationCollapse(forSeeStr) table.insert(strList, forSeeStr) end end if options.extratext then table.insert(strList, punctuationCollapse(options.extratext..'.')) end -- Return the concatenated list return table.concat(strList, ' ') end -- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps -- but not blank/whitespace values. Ignores named args and args < "from". function p._forSee (args, from, options) local forSeeTable = p.forSeeArgsToTable(args, from, options) return p.forSeeTableToString(forSeeTable, options) end -- As _forSee, but uses the frame. function p.forSee (frame, from, options) mArguments = require('Module:Arguments') return p._forSee(mArguments.getArgs(frame), from, options) end return p d0828422b1aa0d0d0092d699d059c9e882260398 Module:Yesno 828 51 101 100 2024-01-11T08:38:10Z EvaTheServal 2 1 revision imported Scribunto text/plain -- Imported from: https://en.wikipedia.org/wiki/Module:Yesno -- Function allowing for consistent treatment of boolean-like wikitext input. -- It works similarly to the template {{yesno}}. return function (val, default) -- If your wiki uses non-ascii characters for any of "yes", "no", etc., you -- should replace "val:lower()" with "mw.ustring.lower(val)" in the -- following line. val = type(val) == 'string' and val:lower() or val if val == nil then return nil elseif val == true or val == 'yes' or val == 'y' or val == 'true' or val == 't' or val == 'on' or val == 'ja' or tonumber(val) == 1 then return true elseif val == false or val == 'no' or val == 'n' or val == 'false' or val == 'f' or val == 'off' or val == 'nein' or tonumber(val) == 0 then return false else return default end end 4cb9790f60303552aa5d331d9ab52f0a3e1f266e Template:Documentation 10 52 103 102 2024-01-11T08:38:11Z EvaTheServal 2 1 revision imported wikitext text/x-wiki <includeonly>{{#invoke:Documentation|doc}}__NOEDITSECTION__{{#seo: |type = website |description = {{FULLPAGENAME}} is a template page used on the Star Citizen Wiki. Templates are pages that are embedded (transcluded) into other pages to allow for the repetition of information. |site_name = Star Citizen Wiki |locale = {{PAGELANGUAGE}} }}</includeonly><noinclude>{{/doc}}</noinclude> 2690a5347936db4ace54fe94a0b3092b6bb04a37 Template:Documentation/styles.css 10 53 105 104 2024-01-11T08:38:12Z EvaTheServal 2 1 revision imported text text/plain .documentation { display: flex; box-sizing: border-box; flex-direction: column; margin: 1.6rem 0; padding-top: 1.6rem; border-top: 1px solid; border-color: var( --border-color-base ); border-radius: var( --border-radius--medium ); font-size: 0.875rem; } .documentation-header { margin-top: 0; margin-bottom: 0.8rem; color: var( --color-base--emphasized ); font-size: 1.25rem; font-weight: 600; line-height: 1.2; } .documentation-subheader { margin: -0.6rem 0 1.6rem 0; color: var( --color-base--subtle ); font-size: 0.825rem; } .documentation-links { margin: 0.3rem 0; float: right; font-family: monospace; font-size: 0.875rem; font-weight: 400; } .documentation-modulestats { display: flex; align-items: center; justify-content: space-between; } .documentation-modulestats .wikitable{ margin: 0; } /** * Tooltip styles used by DependencyList, * shouldn't be here but it is only used here anyways */ .hatnote-container { position: relative; } .tooltip-trigger { padding: 0.2rem 0.5rem; margin-right: 2px; background: var( --color-primary ); border-radius: 100px; color: #fff; } .tooltip-trigger:hover { background: var( --color-primary--hover ); } .tooltip-content { position: absolute; z-index: 1; right: 0; padding: 15px; background-color: var( --color-surface-1 ); border-radius: var( --border-radius--medium ); box-shadow: 0 14px 28px rgba( 0, 0, 0, 0.06 ), 0 10px 10px rgba( 0, 0, 0, 0.06 ); visibility: hidden; } .tooltip-content > ol { margin-top: 0; margin-left: 1.2rem; } .tooltip-content:hover, .tooltip-trigger:hover + .tooltip-content { visibility: visible; } 7cedb77e3d7d2055318ceaf9b5e24342b73243ce Module:DPLlua 828 54 107 106 2024-01-11T08:38:13Z EvaTheServal 2 1 revision imported Scribunto text/plain -- <nowiki> local dpl = {} local libraryUtil = require( 'libraryUtil' ) local hasContent = require( 'Module:Paramtest' ).has_content local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg dpl.pipe = '¦' local dataContentMarker = '`#@@#`' local allIncludedParamNames = {} -- Custom function for splitting a string because mw.text.split() is waaay too slow local function split( str, pattern, plain ) local res = {} local continue = true local startIndex = 1 while continue do local i, j = string.find( str, pattern, startIndex, plain ) if i then table.insert( res, string.sub( str, startIndex, i-1 ) ) startIndex = j + 1 else table.insert( res, string.sub( str, startIndex ) ) continue = false end end return res end -- Also custom function for speed local function trim( str ) return (string.gsub( str, '^%s+', '' ):gsub( '%s+$', '' )) end local function mergeItem( tbl, key, item ) if type( tbl[key] ) == 'table' and type( item ) == 'table' then for k in pairs( tbl[key] ) do mergeItem( tbl[key], k, item[k] ) end elseif type( tbl[key] ) == 'table' then table.insert( tbl[key], item ) else tbl[key] = { tbl[key], item } end end local escapeChars = { ['{'] = '&#123;', ['}'] = '&#125;', ['['] = '&#91;', [']'] = '&#93;', ['|'] = '&#124;', ['-'] = '&#8208;' } local function escape( str ) return (string.gsub( str, '[{}%[%]|%-]', escapeChars )) end local unEscapeChars = { ['&#123;'] = '{', ['&#125;'] = '}', ['&#91;'] = '[', ['&#93;'] = ']', ['&#124;'] = '|', ['&#8208;'] = '-' } local function unEscape( str ) return (string.gsub( str, '&#%d+;', unEscapeChars )) end local function fixCurlyBrackets( str ) -- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so -- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow. return (string.gsub( str, '\226\157[\180\181]', { ['❴'] = '{', ['❵'] = '}' } )) end local function removeFormattingSettings( query ) local toRemove = { 'mode', 'table', 'tablerow', 'tablesortcol', 'headingmode', 'headingcount', 'listattr', 'itemattr', 'hlistattr', 'hitemattr', 'userdateformat', 'shownamespace', 'escapelinks', 'titlemaxlength', 'replaceintitle', 'columns', 'rows', 'rowsize', 'rowcolformat', 'resultsheader', 'resultsfooter', 'oneresultheader', 'oneresultfooter', 'noresultsheader', 'suppresserrors', 'noresultsfooter', 'format', 'groupMultiTemplateResults' } for _, k in ipairs( toRemove ) do query[k] = nil end end local function formatInclude( query ) checkTypeForNamedArg( 'Module:DPLlua.ask', 'include', query, 'string' ) query = split( query, ',', true ) local includedParamNames = {} local sectionAttributes = {} for i = 1, #query do if query[i]:match( '%b{}' ) then -- Check if we are including a template local templateName, extra = query[i]:match( '{(.-)[¦|}](.*)' ) if hasContent( extra ) then local phantomTemplateName = extra:match( '^(.-)}' ) or extra:match( '^[./].+' ) local phantomTemplatePrefix = extra:match( '^(.-)}' ) and '' or templateName local params = extra:gsub( '^.-}', '' ):gsub( '^[./].+', '' ):gsub( ':%-', '' ) local sur = hasContent( phantomTemplateName ) and ('¦' .. phantomTemplatePrefix .. phantomTemplateName) or '' query[i] = string.format( '{%s%s}%s', templateName, sur, params ) if hasContent( phantomTemplateName ) then table.insert( includedParamNames, { name=phantomTemplatePrefix..phantomTemplateName, isTemplate=true, hasPhantomTemplate=true } ) table.insert( sectionAttributes, { hasPhantomTemplate=true } ) else for param in params:gmatch( ':([^:]*)' ) do param = trim( param ) table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } ) end table.insert( sectionAttributes, { hasPhantomTemplate=false } ) end else query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } ) table.insert( sectionAttributes, { hasPhantomTemplate=false } ) end else table.insert( includedParamNames, { name=trim( query[i] ) } ) table.insert( sectionAttributes, { hasPhantomTemplate=false } ) end end return table.concat( query, ',' ), includedParamNames, sectionAttributes end local function formatDpl( query ) local queries = {} local count = query.count or 500 local offset = query.offset or 0 local usesInclude = false local includedParamNames = {} local sectionAttributes query.count = nil query.offset = nil -- Use table format so we can place dataContentMarkers around each included parameter. The secseparator -- is needed to add dataContentMarkers when a phantom template is used local dplStringInclude = [=[ {{#dpl: |noresultsheader=@@ |count=%s |offset=%s |%s |table=, |listseparators=,\n¦-\n¦[[%%PAGE%%¦]],, |tablerow=%s |secseparators=%s }}]=] -- Table format requires an include statement so we use format instead. -- This is also a lot faster than adding an empty include statement local dplStringNoInclude = [=[ {{#dpl: |noresultsheader=@@ |count=%s |offset=%s |%s |format=,¦-¦[[%%PAGE%%¦]],, }}]=] -- Auto generate more than one dpl if count > 500 -- The results of these are later combined for i = 1, math.ceil( count / 500 ) do local params = {} for k, v in pairs( query ) do if k == 'include' then v, includedParamNames, sectionAttributes = formatInclude( v ) usesInclude = true end if type( v ) == 'table' then for _, x in ipairs( v ) do table.insert( params, k .. '=' .. tostring( x ):gsub( '|', '¦' ) ) end else table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) ) end end if usesInclude then local secseparators = '' for _, v in ipairs( sectionAttributes ) do if v.hasPhantomTemplate then -- Phantom templates need this because they ignore tablerow formatting secseparators = secseparators .. '¶¦' .. dataContentMarker .. ',' .. dataContentMarker .. ',' else secseparators = secseparators .. '¶¦,,' end end table.insert( queries, string.format( dplStringInclude, count > 500 and 500 or count, offset, table.concat( params, '\n|' ), string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ), secseparators ) ) else table.insert( queries, string.format( dplStringNoInclude, count > 500 and 500 or count, offset, table.concat( params, '\n|' ) ) ) end count = count - 500 offset = offset + 500 end table.insert( allIncludedParamNames, includedParamNames ) return table.concat( queries ) end local function toTable( query, groupMultiTemplateResults ) local includedParamNames = table.remove( allIncludedParamNames, 1 ) local usesInclude = #includedParamNames > 0 local res = {} query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end ) if query:find( '^@@' ) then -- @@ is used when no result is found return res end if usesInclude then query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape ) end query = trim( query ) query = split( query, '|-', true ) -- Results of the returned pages are separated by |- for _, v in ipairs( query ) do if hasContent( v ) and not v:find( '^@@' ) then v = trim( v ) local title = v:match( '^|%[%[(.-)|' ) local rawDataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title if not usesInclude then if title and title ~= '' then table.insert( res, title ) end else -- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) their results are separated by a pipe rawDataList = split( rawDataList, '|', true ) local cleanedDataList = {} for _incIndex, dataItem in ipairs( rawDataList ) do local incIndex = ((_incIndex - 1) % #includedParamNames) + 1 -- Needed in case the same template appears multiple times on the same page dataItem = unEscape( dataItem ) dataItem = trim( dataItem ) if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template -- When we include an entire template we use the %ARGS% parameter supplied by dpl. -- However all | characters are repaced with §, e.g.: -- §namelessParam -- §param = text [[wowee§link text]] -- §param2 = text {{something§something else}} dataItem = dataItem:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end ) dataItem = mw.text.unstripNoWiki( dataItem ) -- Unstrip nowiki so we can clean their content dataItem = fixCurlyBrackets( dataItem ) -- When using the %ARGS% dpl parameter, curly brackets are replaced with ❴ (U+2774) and ❵ (U+2775) dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end ) dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki local _dataItem = {} if dataItem ~= '' then dataItem = split( dataItem:sub( 3 ), '§' ) -- The sub(3) removes the first § at the start. § is 2 bytes wide so start at index 3 for i, item in ipairs( dataItem ) do if item:find( '=' ) then -- Check if the parameter is named or unnamed local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' ) _dataItem[ param ] = value else table.insert( _dataItem, trim( item ) ) end end end dataItem = _dataItem end local dataListIndex = groupMultiTemplateResults and 1 or math.ceil( _incIndex / #includedParamNames ) if includedParamNames[ incIndex ].isTemplate and not includedParamNames[ incIndex ].includeAll and not includedParamNames[ incIndex ].hasPhantomTemplate then -- This means there was an include in the form 'include = {template}:param' local templateName = includedParamNames[ incIndex ].name local paramName = includedParamNames[ incIndex ].param paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {} cleanedDataList[ dataListIndex ][ templateName ] = cleanedDataList[ dataListIndex ][ templateName ] or {} if groupMultiTemplateResults and _incIndex > #includedParamNames then mergeItem( cleanedDataList[ dataListIndex ][ templateName ], paramName, dataItem ) else cleanedDataList[ dataListIndex ][ templateName ][ paramName ] = dataItem end else local templateName = includedParamNames[ incIndex ].name cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {} if groupMultiTemplateResults and _incIndex > #includedParamNames then mergeItem( cleanedDataList[ dataListIndex ], templateName, dataItem ) else cleanedDataList[ dataListIndex ][ templateName ] = dataItem end end end if title and title ~= '' then for _, v in ipairs( cleanedDataList ) do table.insert( res, { title=title, include=v } ) end end end end end return res end -- Accepts a series of tables each containig the settings for a dpl query. -- Combinig multiple dpl queries yields better performance than doing them sequentially function dpl.ask( ... ) local formatTime = os.clock() local queries = { ... } local wantsGrouping = {} for i = 1, #queries do checkType( 'Module:DPLlua.ask', i, queries[i], 'table' ) table.insert( wantsGrouping, queries[i].groupMultiTemplateResults or false ) removeFormattingSettings( queries[i] ) queries[i] = formatDpl( queries[i] ) end formatTime = os.clock() - formatTime local DPLtime = os.clock() queries = table.concat( queries, '$@µ@$' ) queries = mw.getCurrentFrame():preprocess( queries ) queries = split( queries, '$@µ@$', true ) DPLtime = os.clock() - DPLtime for i = 1, #queries do local parseTime = os.clock() queries[i] = toTable( queries[i], wantsGrouping[i] ) parseTime = os.clock() - parseTime queries[i]['DPL time'] = DPLtime queries[i]['Parse time'] = math.floor( (formatTime + parseTime) * 1e5 ) / 1e5 -- os.clock() has a resolution of 10µs end return unpack( queries ) end -- function dpl.test() -- local time = os.clock() -- local a, b = dpl.ask({ -- namespace = 'Module', -- linksto = 'Module:Chart data', -- distinct = 'strict', -- ordermethod = 'title', -- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data', -- ignorecase = 'true', -- allowcachedresults = false -- },{ -- namespace = 'Module', -- linksto = 'Module:Enum', -- distinct = 'strict', -- ordermethod = 'title', -- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Enum', -- ignorecase = 'true', -- allowcachedresults = false -- }) -- mw.logObject(a) -- mw.logObject(b) -- local a, b = dpl.ask({ -- namespace = 'Module', -- linksto = 'Module:Chart data', -- distinct = 'strict', -- ordermethod = 'title', -- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data', -- ignorecase = 'true', -- allowcachedresults = false -- },{ -- namespace = '', -- ignorecase = 'true', -- uses = 'Template:Infobox Recipe', -- count = 50, -- include = '{Infobox Recipe},{Infobox Item}', -- allowcachedresults = false -- }) -- mw.logObject(a) -- mw.logObject(b) -- local a = dpl.ask{ -- namespace = '', -- uses = 'Template:Infobox Recipe', -- include = '{Infobox Recipe}:skill:name,{Infobox Item}:update,{Infobox Item|test}', -- count = 50, -- ordermethod = 'title', -- } -- mw.logObject(a) -- local q = dpl.ask{ -- uses = "Template:Collections table", -- category = "Archaeology collections", -- -- include = "{Infobox collection}:reward,{Collections table}:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15", -- include = "{Infobox collection}:reward,{Collections table}", -- count = 100 -- } -- mw.logObject(q) -- local q = dpl.ask{ -- namespace = "", -- uses = "Template:Infobox spell", -- notcategory = {"Removed content", "Removed spells"}, -- nottitlematch = {"Enchant Crossbow Bolt", "Storm of Armadyl"}, -- include = "{Infobox spell}", -- } -- mw.logObject(q) -- local list = dpl.ask{ -- namespace = 'Template', -- uses = 'Template:Navbox', -- ordermethod = 'title', -- include = '{Navbox}:gtitle1:gtitle2', -- count = 1, -- offset = 3 -- } -- mw.logObject(list) -- local list = dpl.ask{ -- namespace = 'User', -- titlematch = 'CephHunter/Sandbox/test1', -- include = '{User:CephHunter/Sandbox/test2|User:CephHunter/Sandbox/test3},{User:CephHunter/Sandbox/test3}:1', -- } -- mw.logObject(list) -- mw.logObject(dpl.ask{ -- namespace = 'User', -- ignorecase = 'true', -- titlematch = 'CephHunter/Sandbox/test1', -- include = '{User:CephHunter/Sandbox/test2}' -- }) -- mw.logObject(dpl.ask{ -- namespace = 'Module', -- uses = 'Template:Helper module', -- titlematch = '%/doc', -- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%', -- ordermethod = 'title', -- include = '{Helper module}, {Helper module}:example', -- count = 1, -- offset = 13 -- }) -- mw.logObject(dpl.ask{ -- namespace = 'Module', -- titlematch = 'Chart data|Absorbative calculator', -- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%|%/doc|DPLlua%', -- ordermethod = 'title', -- include = '%0' -- }) -- mw.logObject(dpl.ask{ -- uses = 'Template:Collections table', -- include = '{Collections table}', -- count = 5 -- }) -- mw.log(os.clock()-time) -- end return dpl -- </nowiki> a4585a9ed619b57adfaa5cf8d9279da529e74df5 Module:DependencyList 828 55 109 108 2024-01-11T08:38:14Z EvaTheServal 2 1 revision imported Scribunto text/plain require("strict"); local p = {} local libraryUtil = require( 'libraryUtil' ) local arr = require( 'Module:Array' ) local yn = require( 'Module:Yesno' ) local param = require( 'Module:Paramtest' ) local dpl = require( 'Module:DPLlua' ) local userError = require("Module:User error") local mHatnote = require('Module:Hatnote') local mHatlist = require('Module:Hatnote list') local moduleIsUsed = false local COLLAPSE_LIST_LENGTH_THRESHOLD = 1 local MAX_DYNAMIC_REQUIRE_LIST_LENGTH = 30 local dynamicRequireListQueryCache = {} local builtins = { --[[ ["libraryUtil"] = { link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#libraryUtil", categories = {}, } ]] ["strict"] = { link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#strict", categories = { "Strict mode modules" }, }, }; --- Used in case 'require( varName )' is found. Attempts to find a string value stored in 'varName'. ---@param content string The content of the module to search in ---@param varName string ---@return string local function substVarValue( content, varName ) local res = content:match( varName .. '%s*=%s*(%b""%s-%.*)' ) or content:match( varName .. "%s*=%s*(%b''%s-%.*)" ) or '' if res:find( '^(["\'])[Mm]odule:[%S]+%1' ) and not res:find( '%.%.' ) and not res:find( '%%%a' ) then return mw.text.trim( res ) else return '' end end ---@param capture string ---@param content string The content of the module to search in ---@return string local function extractModuleName( capture, content ) capture = capture:gsub( '^%(%s*(.-)%s*%)$', '%1' ) if capture:find( '^(["\']).-%1$' ) then -- Check if it is already a pure string return capture elseif capture:find( '^[%a_][%w_]*$' ) then -- Check if if is a single variable return substVarValue( content, capture ) end return capture end ---@param str string ---@return string local function formatPageName( str ) local name = mw.text.trim(str) :gsub( '^([\'\"])(.-)%1$', function(_, x) return x end ) -- Only remove quotes at start and end of string if both are the same type :gsub( '_', ' ' ) :gsub( '^.', string.upper ) :gsub( ':.', string.upper ) return name end ---@param str string ---@return string local function formatModuleName( str, allowBuiltins ) if allowBuiltins then local name = mw.text.trim(str) -- Only remove quotes at start and end of string if both are the same type :gsub([[^(['"])(.-)%1$]], function(_, x) return x end); local builtin = builtins[name]; if builtin then return builtin.link .. "|" .. name, builtin; end end local module = formatPageName( str ) if not string.find( module, '^[Mm]odule:' ) then module = 'Module:' .. module end return module end local function dualGmatch( str, pat1, pat2 ) local f1 = string.gmatch( str, pat1 ) local f2 = string.gmatch( str, pat2 ) return function() return f1() or f2() end end --- Used in case a construct like 'require( "Module:wowee/" .. isTheBest )' is found. --- Will return a list of pages which satisfy this pattern where 'isTheBest' can take any value. ---@param query string ---@return string[] Sequence of strings local function getDynamicRequireList( query ) local isDynamic = true; if query:find( '%.%.' ) then query = mw.text.split( query, '..', true ) query = arr.map( query, function(x) return mw.text.trim(x) end ) query = arr.map( query, function(x) return (x:match('^[\'\"](.-)[\'\"]$') or '%') end ) query = table.concat( query ) else local _; _, query = query:match( '(["\'])(.-)%1' ) if query == nil then return {}, isDynamic end local replacements; query, replacements = query:gsub( '%%%a', '%%' ) if replacements == 0 then isDynamic = false; end end query = query:gsub( '^[Mm]odule:', '' ) if query:find( '^[Dd]ata/' ) then return { 'Module:' .. query }, isDynamic; -- This format will later be used by formatDynamicQueryLink() end if dynamicRequireListQueryCache[ query ] then return dynamicRequireListQueryCache[ query ], isDynamic; end local list = dpl.ask{ namespace = 'Module', titlematch = query, nottitlematch = '%/doc|'..query..'/%', distinct = 'strict', ignorecase = true, ordermethod = 'title', count = MAX_DYNAMIC_REQUIRE_LIST_LENGTH + 1, skipthispage = 'no', allowcachedresults = true, cacheperiod = 604800 -- One week } if #list > MAX_DYNAMIC_REQUIRE_LIST_LENGTH then list = { 'Module:' .. query } end dynamicRequireListQueryCache[ query ] = list return list, isDynamic; end --- Returns a list of modules loaded and required by module 'moduleName'. ---@param moduleName string ---@param searchForUsedTemplates boolean ---@return string[], string[], string[], string[] local function getRequireList( moduleName, searchForUsedTemplates ) local content = mw.title.new( moduleName ):getContent() local requireList = arr{} local loadDataList = arr{} local usedTemplateList = arr{} local dynamicRequirelist = arr{} local dynamicLoadDataList = arr{} local extraCategories = arr{} assert( content ~= nil, string.format( '%s does not exist', moduleName ) ) content = content:gsub( '%-%-%[(=-)%[.-%]%1%]', '' ):gsub( '%-%-[^\n]*', '' ) -- Strip comments for match in dualGmatch( content, 'require%s*(%b())', 'require%s*((["\'])%s*[Mm]odule:.-%2)' ) do match = mw.text.trim( match ) match = extractModuleName( match, content ) if match:find( '%.%.' ) or match:find( '%%%a' ) then for _, x in ipairs( getDynamicRequireList( match ) ) do table.insert( dynamicRequirelist, x ) end elseif match ~= '' then local builtin; match, builtin = formatModuleName( match, true ) table.insert( requireList, match ) if builtin then local builtinCategories = builtin.categories; if type(builtinCategories) == "table" then for _, x in ipairs(builtinCategories) do table.insert(extraCategories, x); end end end end end for match in dualGmatch( content, 'mw%.loadData%s*(%b())', 'mw%.loadData%s*((["\'])%s*[Mm]odule:.-%2)' ) do match = mw.text.trim( match ) match = extractModuleName( match, content ) if match:find( '%.%.' ) or match:find( '%%%a' ) then for _, x in ipairs( getDynamicRequireList( match ) ) do table.insert( dynamicLoadDataList, x ) end elseif match ~= '' then match = formatModuleName( match, true ) table.insert( loadDataList, match ) end end for match in dualGmatch( content, 'mw%.loadJsonData%s*(%b())', 'mw%.loadJsonData%s*((["\'])%s*[Mm]odule:.-%2)' ) do match = mw.text.trim( match ) match = extractModuleName( match, content ) if match:find( '%.%.' ) or match:find( '%%%a' ) then for _, x in ipairs( getDynamicRequireList( match ) ) do table.insert( dynamicLoadDataList, x ) end elseif match ~= '' then match = formatModuleName( match, true ) table.insert( loadDataList, match ) end end for func, match in string.gmatch( content, 'pcall%s*%(([^,]+),([^%),]+)' ) do func = mw.text.trim( func ) match = mw.text.trim( match ) local dynList, isDynamic; if func == 'require' then dynList, isDynamic = getDynamicRequireList(match); if (isDynamic == false and #dynList == 1) then table.insert(requireList, dynList[1]); else for _, x in ipairs(dynList) do table.insert( dynamicRequirelist, x ) end end elseif func == 'mw.loadData' then dynList, isDynamic = getDynamicRequireList(match); if (isDynamic == false and #dynList == 1) then table.insert(loadDataList, dynList[1]); else for _, x in ipairs(dynList) do table.insert( dynamicLoadDataList, x ) end end end end if searchForUsedTemplates then for preprocess in string.gmatch( content, ':preprocess%s*(%b())' ) do local function recursiveGMatch( str, pat ) local list = {} local i = 0 repeat for match in string.gmatch( list[i] or str, pat ) do table.insert( list, match ) end i = i + 1 until i > #list or i > 100 i = 0 return function() i = i + 1 return list[i] end end for template in recursiveGMatch( preprocess, '{(%b{})}' ) do local name = string.match( template, '{(.-)[|{}]' ) if name ~= '' then if name:find( ':' ) then local ns = name:match( '^(.-):' ) if arr.contains( {'', 'template', 'user'}, ns:lower() ) then table.insert( usedTemplateList, name ) elseif ns == ns:upper() then table.insert( usedTemplateList, ns ) -- Probably a magic word end else if name:match( '^%u+$' ) or name == '!' then table.insert( usedTemplateList, name ) -- Probably a magic word else table.insert( usedTemplateList, 'Template:'..name ) end end end end end end requireList = requireList .. dynamicRequirelist:reject( loadDataList ) requireList = requireList:unique() loadDataList = loadDataList .. dynamicLoadDataList:reject( requireList ) loadDataList = loadDataList:unique() usedTemplateList = usedTemplateList:unique() extraCategories = extraCategories:unique() table.sort( requireList ) table.sort( loadDataList ) table.sort( usedTemplateList ) table.sort( extraCategories ) return requireList, loadDataList, usedTemplateList, extraCategories end --- Returns a list with module and function names used in all '{{#Invoke:moduleName|funcName}}' found on page 'templateName'. ---@param templateName string ---@return table<string, string>[] local function getInvokeCallList( templateName ) local content = mw.title.new( templateName ):getContent() local invokeList = {} assert( content ~= nil, string.format( '%s does not exist', templateName ) ) for moduleName, funcName in string.gmatch( content, '{{[{|safeubt:}]-#[Ii]nvoke:([^|]+)|([^}|]+)[^}]*}}' ) do moduleName = formatModuleName( moduleName ) funcName = mw.text.trim( funcName ) if string.find( funcName, '^{{{' ) then funcName = funcName .. '}}}' end table.insert( invokeList, {moduleName=moduleName, funcName=funcName} ) end invokeList = arr.unique( invokeList, function(x) return x.moduleName..x.funcName end ) table.sort( invokeList, function(x, y) return x.moduleName..x.funcName < y.moduleName..y.funcName end ) return invokeList end ---@param pageName string ---@param addCategories boolean ---@return string local function messageBoxUnused( pageName, addCategories ) local mbox = require( 'Module:Mbox' )._mbox local category = addCategories and '[[Category:Unused modules]]' or '' return mbox( 'This module is unused.', string.format( 'This module is neither invoked by a template nor required/loaded by another module. If this is in error, make sure to add <code>{{[[Template:Documentation|Documentation]]}}</code>/<code>{{[[Template:No documentation|No&nbsp;documentation]]}}</code> to the calling template\'s or parent\'s module documentation.', pageName ), { icon = 'WikimediaUI-Alert.svg' } ) .. category end local function collapseList( list, id, listType ) local text = string.format( '%d %s', #list, listType ) local button = '<span>' .. text .. ':</span>&nbsp;' local content = mHatlist.andList( list, false ) return { tostring( button ) .. tostring( content ) } end --- Creates a link to [[Special:Search]] showing all pages found by getDynamicRequireList() in case it found more than MAX_DYNAMIC_REQUIRE_LIST_LENGTH pages. ---@param query string @This will be in a format like 'Module:Wowee/%' or 'Module:Wowee/%/data' ---@return string local function formatDynamicQueryLink( query ) local prefix = query:match( '^([^/]+)' ) local linkText = query:gsub( '%%', '&lt; ... &gt;' ) query = query:gsub( '^Module:', '' ) query = query:gsub( '([^/]+)/?', function ( match ) if match == '%' then return '\\/[^\\/]+' else return '\\/"' .. match .. '"' end end ) query = query:gsub( '^\\/', '' ) query = string.format( 'intitle:/%s%s/i -intitle:/%s\\/""/i -intitle:doc prefix:"%s"', query, query:find( '"$' ) and '' or '""', query, prefix ) return string.format( '<span class="plainlinks">[%s %s]</span>', tostring( mw.uri.fullUrl( 'Special:Search', { search = query } ) ), linkText ) end ---@param templateName string ---@param addCategories boolean ---@param invokeList table<string, string>[] @This is the list returned by getInvokeCallList() ---@return string local function formatInvokeCallList( templateName, addCategories, invokeList ) local category = addCategories and '[[Category:Lua-based templates]]' or '' local res = {} for _, item in ipairs( invokeList ) do local msg = string.format( "'''%s''' invokes function '''%s''' in [[%s]] using [[Star Citizen:Lua|Lua]].", templateName, item.funcName, item.moduleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #invokeList > 0 then table.insert( res, category ) end return table.concat( res ) end ---@param moduleName string ---@param addCategories boolean ---@param whatLinksHere string @A list generated by a dpl of pages in the Template namespace which link to moduleName. ---@return string local function formatInvokedByList( moduleName, addCategories, whatLinksHere ) local function lcfirst( str ) return string.gsub( str, '^[Mm]odule:.', string.lower ) end local templateData = arr.map( whatLinksHere, function(x) return {templateName=x, invokeList=getInvokeCallList(x)} end ) templateData = arr.filter( templateData, function(x) return arr.any( x.invokeList, function(y) return lcfirst(y.moduleName) == lcfirst(moduleName) end ) end ) local invokedByList = {} for _, template in ipairs( templateData ) do for _, invoke in ipairs( template.invokeList ) do table.insert( invokedByList, string.format( "function '''%s''' is invoked by [[%s]]", invoke.funcName, template.templateName ) ) end end table.sort( invokedByList) local res = {} if #invokedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then local msg = string.format( "'''%s''' is invoked by %s.", moduleName, collapseList( invokedByList, 'invokedBy', 'templates' )[1] ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) else for _, item in ipairs( invokedByList ) do local msg = string.format( "'''%s's''' %s.", moduleName, item ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end end if #templateData > 0 then moduleIsUsed = true table.insert( res, (addCategories and '[[Category:Template invoked modules]]' or '') ) end return table.concat( res ) end ---@param moduleName string ---@param addCategories boolean ---@param whatLinksHere string @A list generated by a dpl of pages in the Module namespace which link to moduleName. ---@return string local function formatRequiredByList( moduleName, addCategories, whatLinksHere ) local childModuleData = arr.map( whatLinksHere, function ( title ) local requireList, loadDataList = getRequireList( title ) return {name=title, requireList=requireList, loadDataList=loadDataList} end ) local requiredByList = arr.map( childModuleData, function ( item ) if arr.any( item.requireList, function(x) return x:lower()==moduleName:lower() end ) then if item.name:find( '%%' ) then return formatDynamicQueryLink( item.name ) else return '[[' .. item.name .. ']]' end end end ) local loadedByList = arr.map( childModuleData, function ( item ) if arr.any( item.loadDataList, function(x) return x:lower()==moduleName:lower() end ) then if item.name:find( '%%' ) then return formatDynamicQueryLink( item.name ) else return '[[' .. item.name .. ']]' end end end ) if #requiredByList > 0 or #loadedByList > 0 then moduleIsUsed = true end if #requiredByList > COLLAPSE_LIST_LENGTH_THRESHOLD then requiredByList = collapseList( requiredByList, 'requiredBy', 'modules' ) end if #loadedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then loadedByList = collapseList( loadedByList, 'loadedBy', 'modules' ) end local res = {} for _, requiredByModuleName in ipairs( requiredByList ) do local msg = string.format( "'''%s''' is required by %s.", moduleName, requiredByModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #requiredByList > 0 then table.insert( res, (addCategories and '[[Category:Modules required by modules]]' or '') ) end for _, loadedByModuleName in ipairs( loadedByList ) do local msg = string.format( "'''%s''' is loaded by %s.", moduleName, requiredByModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #loadedByList > 0 then table.insert( res, (addCategories and '[[Category:Module data]]' or '') ) end return table.concat( res ) end local function formatRequireList( currentPageName, addCategories, requireList ) local res = {} if #requireList > COLLAPSE_LIST_LENGTH_THRESHOLD then requireList = collapseList( requireList, 'require', 'modules' ) end for _, requiredModuleName in ipairs( requireList ) do local msg = string.format( "'''%s''' requires %s.", currentPageName, requiredModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #requireList > 0 then table.insert( res, (addCategories and '[[Category:Modules requiring modules]]' or '') ) end return table.concat( res ) end local function formatLoadDataList( currentPageName, addCategories, loadDataList ) local res = {} if #loadDataList > COLLAPSE_LIST_LENGTH_THRESHOLD then loadDataList = collapseList( loadDataList, 'loadData', 'modules' ) end for _, loadedModuleName in ipairs( loadDataList ) do local msg = string.format( "'''%s''' loads data from %s.", currentPageName, loadedModuleName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end if #loadDataList > 0 then table.insert( res, (addCategories and '[[Category:Modules using data]]' or '') ) end return table.concat( res ) end local function formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList ) local res = {} if #usedTemplateList > COLLAPSE_LIST_LENGTH_THRESHOLD then usedTemplateList = collapseList( usedTemplateList, 'usedTemplates', 'templates' ) end for _, templateName in ipairs( usedTemplateList ) do local msg = string.format( "'''%s''' transcludes [[%s]] using <samp>frame:preprocess()</samp>.", currentPageName, templateName ) table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) ) end return table.concat( res ) end function p.main( frame ) local args = frame:getParent().args return p._main( args[1], args.category, args.isUsed ) end ---@param currentPageName string|nil ---@param addCategories boolean|string|nil ---@return string function p._main( currentPageName, addCategories, isUsed ) libraryUtil.checkType( 'Module:RequireList._main', 1, currentPageName, 'string', true ) libraryUtil.checkTypeMulti( 'Module:RequireList._main', 2, addCategories, {'boolean', 'string', 'nil'} ) libraryUtil.checkTypeMulti( 'Module:RequireList._main', 3, isUsed, {'boolean', 'string', 'nil'} ) local title = mw.title.getCurrentTitle() -- Leave early if not in module or template namespace if param.is_empty( currentPageName ) and ( not arr.contains( {'Module', 'Template'}, title.nsText ) ) then return '' end currentPageName = param.default_to( currentPageName, title.fullText ) currentPageName = string.gsub( currentPageName, '/[Dd]oc$', '' ) currentPageName = formatPageName( currentPageName ) addCategories = yn( param.default_to( addCategories, title.subpageText~='doc' ) ) moduleIsUsed = yn( param.default_to( isUsed, false ) ) if title.text:lower():find( 'sandbox' ) then moduleIsUsed = true -- Don't show sandbox modules as unused end if currentPageName:find( '^Template:' ) then local ok, invokeList = pcall( getInvokeCallList, currentPageName ) if ok then return formatInvokeCallList( currentPageName, addCategories, invokeList ) else return userError(invokeList) end end local whatTemplatesLinkHere, whatModulesLinkHere = dpl.ask( { namespace = 'Template', linksto = currentPageName, distinct = 'strict', ignorecase = true, ordermethod = 'title', allowcachedresults = true, cacheperiod = 604800 -- One week }, { namespace = 'Module', linksto = currentPageName, nottitlematch = '%/doc%|' .. currentPageName:gsub( 'Module:', '' ), distinct = 'strict', ignorecase = true, ordermethod = 'title', allowcachedresults = true, cacheperiod = 604800 -- One week } ) local requireList, loadDataList, usedTemplateList, extraCategories; do local ok; ok, requireList, loadDataList, usedTemplateList, extraCategories = pcall(getRequireList, currentPageName, true); if not ok then return userError(requireList); end end requireList = arr.map( requireList, function ( moduleName ) if moduleName:find( '%%' ) then return formatDynamicQueryLink( moduleName ) else return '[[' .. moduleName .. ']]' end end ) loadDataList = arr.map( loadDataList, function ( moduleName ) if moduleName:find( '%%' ) then return formatDynamicQueryLink( moduleName ) else return '[[' .. moduleName .. ']]' end end ) usedTemplateList = arr.map( usedTemplateList, function( templateName ) if string.find( templateName, ':' ) then -- Real templates are prefixed by a namespace, magic words are not return '[['..templateName..']]' else return "'''&#123;&#123;"..templateName.."&#125;&#125;'''" -- Magic words don't have a page so make them bold instead end end ) local res = {} table.insert( res, formatInvokedByList( currentPageName, addCategories, whatTemplatesLinkHere ) ) table.insert( res, formatRequireList( currentPageName, addCategories, requireList ) ) table.insert( res, formatLoadDataList( currentPageName, addCategories, loadDataList ) ) table.insert( res, formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList ) ) table.insert( res, formatRequiredByList( currentPageName, addCategories, whatModulesLinkHere ) ) if addCategories then extraCategories = arr.map(extraCategories, function(categoryName) return "[[Category:" .. categoryName .. "]]"; end); table.insert(res, table.concat(extraCategories)); end if not moduleIsUsed then table.insert( res, 1, messageBoxUnused( currentPageName:gsub( 'Module:', '' ), addCategories ) ) end return table.concat( res ) end return p -- </nowiki> d5f03ab1075172cdbb69e217ef5ed86f0d973480 Module:Documentation 828 56 111 110 2024-01-11T08:38:15Z EvaTheServal 2 1 revision imported Scribunto text/plain -- <nowiki> local dependencyList = require( 'Module:DependencyList' ) local yn = require( 'Module:Yesno' ) local hatnote = require( 'Module:Hatnote' )._hatnote local mbox = require( 'Module:Mbox' )._mbox local lang = mw.getContentLanguage() local p = {} function p.doc( frame ) local title = mw.title.getCurrentTitle() local args = frame:getParent().args local page = args[1] or mw.ustring.gsub( title.fullText, '/doc$', '' ) local ret, cats, ret1, ret2, ret3 local pageType = title.namespace == 828 and 'module' or 'template' local opts = frame.args; -- subpage header if title.subpageText == 'doc' then ret = mbox( 'This is a documentation subpage for ' .. page .. '.', string.format( 'It contains usage information, categories, and other content that is not part of the [[' .. page .. '|original %s page]].', pageType ), { icon = 'WikimediaUI-Notice.svg' } ) if title.namespace == 10 then -- Template namespace cats = '[[Category:Template documentation|' .. title.baseText .. ']]' ret2 = dependencyList._main() elseif title.namespace == 828 then -- Module namespace cats = '[[Category:Module documentation|' .. title.baseText .. ']]' ret2 = dependencyList._main() ret2 = ret2 .. require('Module:Module toc').main() else cats = '' ret2 = '' end return tostring( ret ) .. ret2 .. cats end -- template header -- don't use mw.html as we aren't closing the main div tag ret1 = '<div class="documentation">' ret2 = mw.html.create( nil ) :tag( 'div' ) :addClass( 'documentation-header' ) :tag( 'span' ) :addClass( 'documentation-title' ) :wikitext( lang:ucfirst( string.format('%s documentation', pageType) ) ) :done() :tag( 'span' ) :addClass( 'documentation-links plainlinks' ) :wikitext( '[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='view'} ) ) .. ' view]]' .. '[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='edit'} ) ) .. ' edit]]' .. '[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='history'} ) ) .. ' history]]' .. '[<span class="jsPurgeLink">[' .. tostring( mw.uri.fullUrl( title.fullText, {action='purge'} ) ) .. ' purge]</span>]' ) :done() :done() :tag( 'div' ) :addClass( 'documentation-subheader' ) :tag( 'span' ) :addClass( 'documentation-documentation' ) :wikitext( 'This documentation is transcluded from [[' .. page .. '/doc]]. Changes can be proposed in the talk page.' ) :done() :wikitext(frame:extensionTag{ name = 'templatestyles', args = { src = 'Documentation/styles.css'} }) :done() ret3 = {} if args.scwShared then --- Message box table.insert( ret3, mbox( string.format( "'''%s''' is [%s%s shared across] the Star Citizen Wikis.", title.fullText, 'https://github.com/The-Star-Citizen-Wikis/SharedModules/tree/master/', mw.uri.encode( title.rootText, 'PATH' ) ), string.format( 'This %s is shared across the Star Citizen Wikis. Any changes should also be relayed to the GitHub repository.', pageType ), { icon = 'WikimediaUI-ArticleDisambiguation-ltr.svg' } ) ) --- Set category table.insert( ret3, string.format( '[[Category:%s shared by the Star Citizen Wikis]]', lang:ucfirst( pageType ) .. 's' ) ) --- Interlanguage link --- TODO: Make this into a for loop when there are more wikis table.insert( ret3, string.format( '[[%s:%s]]', 'de', title.fullText ) ) end if args.fromWikipedia then table.insert( ret3, mbox( string.format( "'''%s''' is imported from [https://en.wikipedia.org/wiki/%s %s] on Wikipedia.", title.fullText, page, page ), string.format( 'This %s is imported from the English Wikipedia. Although the visual appearance might be different, the functionality is identical. Please refer to the Wikipedia page for detailed documentation.', pageType ), { icon = 'WikimediaUI-Logo-Wikipedia.svg' } ) ) --- Set category table.insert( ret3, string.format( '[[Category:%s imported from Wikipedia]]', lang:ucfirst( pageType ) .. 's' ) ) end if title.namespace == 828 then -- Has config if mw.title.new( title.fullText .. '/config.json', 'Module' ).exists then table.insert( ret3, mbox( string.format( "'''%s''' loads configuration from [[%s/config.json]].", title.fullText, title.fullText ), 'This module can be configurated from the config.json subpage.', { icon='WikimediaUI-Settings.svg' } ) ) end -- Has localization if mw.title.new( title.fullText .. '/i18n.json', 'Module' ).exists then table.insert( ret3, mbox( string.format( "'''%s''' loads messages from [[%s/i18n.json]].", title.fullText, title.fullText ), 'This module is designed to be language-neutral. All of the messages are saved in the i18n.json subpage.', { icon='WikimediaUI-Language.svg' } ) ) end -- Testcase page if title.subpageText == 'testcases' then table.insert( ret3, hatnote( string.format( 'This is the test cases page for the module [[Module:%s]].', title.baseText ), { icon='WikimediaUI-LabFlask.svg' } ) ) end end --- Dependency list table.insert( ret3, dependencyList._main( nil, args.category, args.isUsed ) ) -- Has templatestyles if mw.title.new( title.fullText .. '/styles.css' ).exists then table.insert( ret3, hatnote( string.format( "'''%s''' loads styles from [[%s/styles.css]].", title.fullText, title.fullText ), { icon='WikimediaUI-Palette.svg' } ) ) end --- Module stats bar if title.namespace == 828 then table.insert( ret3, '<div class="documentation-modulestats">' ) -- Function list table.insert( ret3, require( 'Module:Module toc' ).main() ) -- Unit tests local testcaseTitle = title.baseText .. '/testcases' if mw.title.new( testcaseTitle, 'Module' ).exists then -- There is probably a better way :P table.insert( ret3, frame:preprocess( '{{#invoke:' .. testcaseTitle .. '|run}}' ) ) end table.insert( ret3, '</div>' ) end return ret1 .. tostring( ret2 ) .. '<div class="documentation-content">' .. table.concat( ret3 ) end return p -- </nowiki> 5a5b6781058f69e3613197f6be6173d07d2bf085 Module:Paramtest 828 57 113 112 2024-01-11T08:38:17Z EvaTheServal 2 1 revision imported Scribunto text/plain -- Imported from: https://runescape.wiki/w/Module:Paramtest --[[ {{Helper module |name=Paramtest |fname1 = is_empty(arg) |ftype1 = String |fuse1 = Returns true if arg is not defined or contains only whitespace |fname2 = has_content(arg) |ftype2 = String |fuse2 = Returns true if arg exists and does not only contain whitespace |fname3 = default_to(arg1,arg2) |ftype3 = String, Any value |fuse3 = If arg1 exists and does not only contain whitespace, the function returns arg1, otherwise returns arg2 |fname4 = defaults{ {arg1,arg2},...} |ftype4 = {String, Any value}... |fuse4 = Does the same as <code>default_to()</code> run over every table passed |fname5 = table_is_empty(arg) |ftype5 = Table |fuse5 = Returns true if the table has no content, it does not check if the content of the table contains anything |fname6 = table_has_content(arg) |ftype6 = Table |fuse6 = returns true if the table has content, it does not check if the content of the table contains anything }} --]] local checkType, checkTypeForNamedArg do local _libraryUtil = require("libraryUtil"); checkType = _libraryUtil.checkType; checkTypeForNamedArg = _libraryUtil.checkTypeForNamedArg; end -- -- Tests basic properties of parameters -- local p = {} -- -- Tests if the parameter is empty, all white space, or undefined -- function p.is_empty(arg) return not string.find(arg or '', '%S') end -- -- Tests if the table parameter is empty -- function p.table_is_empty(arg) for _, _ in pairs(arg) do return false end return true end -- -- Returns the parameter if it has any content, the default (2nd param) -- function p.default_to(arg, default) if string.find(arg or '', '%S') then return arg else return default end end -- -- Returns a list of paramaters if it has any content, or the default -- function p.defaults(args) checkType("defaults", 1, args, "table"); local ret = {} for i, v in ipairs(args) do checkTypeForNamedArg("defaults", i, v, "table"); ret[i] = p.default_to(v[1], v[2]); end return unpack(ret, 1, #args); end -- -- Tests if the parameter has content -- The same as !is_empty, but this is more readily clear -- function p.has_content(arg) return string.find(arg or '', '%S') end -- -- Tests if the table parameter has content -- The same as !table_is_empty, but this is more readily clear -- function p.table_has_content(arg) for _, _ in pairs(arg) do return true end return false end -- -- uppercases first letter -- function p.ucfirst(arg) if not arg or arg:len() == 0 then return nil elseif arg:len() == 1 then return arg:upper() else return arg:sub(1,1):upper() .. arg:sub(2) end end -- -- uppercases first letter, lowercases everything else -- function p.ucflc(arg) if not arg or arg:len() == 0 then return nil elseif arg:len() == 1 then return arg:upper() else return arg:sub(1,1):upper() .. arg:sub(2):lower() end end return p d69422a8379e1fcb190fe16e6d212071b9caa1dc Module:Infobox 828 58 115 114 2024-01-11T08:38:19Z EvaTheServal 2 1 revision imported Scribunto text/plain -- -- This module implements {{Infobox}} -- local p = {} -- local navbar = require('Module:Navbar')._navbar local args = {} local origArgs local root local function notempty( s ) return s and s:match( '%S' ) end local function fixChildBoxes(sval, tt) if notempty(sval) then local marker = '<span class=special_infobox_marker>' local s = sval s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1') s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker) if s:match(marker) then s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '') s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1') s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1') s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1') s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1') s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1') s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1') s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1') s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1') end if s:match(marker) then local subcells = mw.text.split(s, marker) s = '' for k = 1, #subcells do if k == 1 then s = s .. subcells[k] .. '</' .. tt .. '></tr>' elseif k == #subcells then local rowstyle = ' style="display:none"' if notempty(subcells[k]) then rowstyle = '' end s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' .. subcells[k] elseif notempty(subcells[k]) then if (k % 2) == 0 then s = s .. subcells[k] else s = s .. '<tr><' .. tt .. ' colspan=2>\n' .. subcells[k] .. '</' .. tt .. '></tr>' end end end end -- the next two lines add a newline at the end of lists for the PHP parser -- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=849054481 -- remove when [[:phab:T191516]] is fixed or OBE s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n') s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n') s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1') s = mw.ustring.gsub(s, '^(%{%|)', '\n%1') return s else return sval end end local function union(t1, t2) -- Returns the union of the values of two tables, as a sequence. local vals = {} for k, v in pairs(t1) do vals[v] = true end for k, v in pairs(t2) do vals[v] = true end local ret = {} for k, v in pairs(vals) do table.insert(ret, k) end return ret end local function getArgNums(prefix) -- Returns a table containing the numbers of the arguments that exist -- for the specified prefix. For example, if the prefix was 'data', and -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}. local nums = {} for k, v in pairs(args) do local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$') if num then table.insert(nums, tonumber(num)) end end table.sort(nums) return nums end local function addRow(rowArgs) -- Adds a row to the infobox, with either a header cell -- or a label/data cell combination. if rowArgs.header then root :tag('tr') :addClass(rowArgs.rowclass) :cssText(rowArgs.rowstyle) :attr('id', rowArgs.rowid) :tag('th') :attr('colspan', 2) :attr('id', rowArgs.headerid) :addClass(rowArgs.class) :addClass(args.headerclass) ----:css('text-align', 'center') :cssText(args.headerstyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.header, 'th')) elseif rowArgs.data then local row = root:tag('tr') row:addClass(rowArgs.rowclass) row:cssText(rowArgs.rowstyle) row:attr('id', rowArgs.rowid) if rowArgs.label then row :tag('th') :attr('scope', 'row') :attr('id', rowArgs.labelid) :cssText(args.labelstyle) :cssText(rowArgs.rowcellstyle) :wikitext(rowArgs.label) :done() end local dataCell = row:tag('td') if not rowArgs.label then dataCell :attr('colspan', 2) ----:css('text-align', 'center') end dataCell :attr('id', rowArgs.dataid) :addClass(rowArgs.class) :cssText(rowArgs.datastyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.data, 'td')) end end local function renderTitle() if not args.title then return end root :tag('caption') :addClass(args.titleclass) :cssText(args.titlestyle) :wikitext(args.title) end local function renderAboveRow() if not args.above then return end root :tag('tr') :tag('th') :attr('colspan', 2) :addClass(args.aboveclass) --:css('text-align', 'center') --:css('font-size', '125%') --:css('font-weight', 'bold') :cssText(args.abovestyle) :wikitext(fixChildBoxes(args.above,'th')) end local function renderBelowRow() if not args.below then return end root :tag('tr') :tag('td') :attr('colspan', '2') :addClass(args.belowclass) --:css('text-align', 'center') :cssText(args.belowstyle) :wikitext(fixChildBoxes(args.below,'td')) end local function renderSubheaders() if args.subheader then args.subheader1 = args.subheader end if args.subheaderrowclass then args.subheaderrowclass1 = args.subheaderrowclass end local subheadernums = getArgNums('subheader') for k, num in ipairs(subheadernums) do addRow({ data = args['subheader' .. tostring(num)], datastyle = args.subheaderstyle, rowcellstyle = args['subheaderstyle' .. tostring(num)], class = args.subheaderclass, rowclass = args['subheaderrowclass' .. tostring(num)] }) end end local function renderImages() if args.image then args.image1 = args.image end if args.caption then args.caption1 = args.caption end local imagenums = getArgNums('image') for k, num in ipairs(imagenums) do local caption = args['caption' .. tostring(num)] local data = mw.html.create():wikitext(args['image' .. tostring(num)]) if caption then data :tag('div') :cssText(args.captionstyle) :wikitext(caption) end addRow({ data = tostring(data), datastyle = args.imagestyle, class = args.imageclass, rowclass = args['imagerowclass' .. tostring(num)] }) end end local function renderRows() -- Gets the union of the header and data argument numbers, -- and renders them all in order using addRow. local rownums = union(getArgNums('header'), getArgNums('data')) table.sort(rownums) for k, num in ipairs(rownums) do addRow({ header = args['header' .. tostring(num)], label = args['label' .. tostring(num)], data = args['data' .. tostring(num)], datastyle = args.datastyle, class = args['class' .. tostring(num)], rowclass = args['rowclass' .. tostring(num)], rowstyle = args['rowstyle' .. tostring(num)], rowcellstyle = args['rowcellstyle' .. tostring(num)], dataid = args['dataid' .. tostring(num)], labelid = args['labelid' .. tostring(num)], headerid = args['headerid' .. tostring(num)], rowid = args['rowid' .. tostring(num)] }) end end --local function renderNavBar() -- if not args.name then return end -- -- root -- :tag('tr') -- :tag('td') -- :attr('colspan', '2') -- --:css('text-align', 'right') -- :wikitext(navbar{ -- args.name, -- mini = 1, -- }) --end local function renderItalicTitle() local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title']) if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'})) end end local function renderTrackingCategories() if args.decat ~= 'yes' then if args.child == 'yes' then if args.title then root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]') end elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then root:wikitext('[[Category:Articles which use infobox templates with no data rows]]') end end end local function _infobox() -- Specify the overall layout of the infobox, with special settings -- if the infobox is used as a 'child' inside another infobox. if args.child ~= 'yes' then root = mw.html.create('table') root :addClass((args.subbox ~= 'yes') and 'infobox' or nil) :addClass(args.bodyclass) --if args.subbox == 'yes' then --root --:css('padding', '0') --:css('border', 'none') --:css('margin', '-3px') --:css('width', 'auto') --:css('min-width', '100%') --:css('font-size', '100%') --:css('clear', 'none') --:css('float', 'none') --:css('background-color', 'transparent') --else --root --:css('width', '400px') -- Changed from 22em --end root :cssText(args.bodystyle) renderTitle() renderAboveRow() else root = mw.html.create() root :wikitext(args.title) end renderSubheaders() renderImages() renderRows() renderBelowRow() --renderNavBar() renderItalicTitle() renderTrackingCategories() return tostring(root) .. mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Infobox/styles.css' } } end local function preprocessSingleArg(argName) -- If the argument exists and isn't blank, add it to the argument table. -- Blank arguments are treated as nil to match the behaviour of ParserFunctions. if origArgs[argName] and origArgs[argName] ~= '' then args[argName] = origArgs[argName] end end local function preprocessArgs(prefixTable, step) -- Assign the parameters with the given prefixes to the args table, in order, in batches -- of the step size specified. This is to prevent references etc. from appearing in the -- wrong order. The prefixTable should be an array containing tables, each of which has -- two possible fields, a "prefix" string and a "depend" table. The function always parses -- parameters containing the "prefix" string, but only parses parameters in the "depend" -- table if the prefix parameter is present and non-blank. if type(prefixTable) ~= 'table' then error("Non-table value detected for the prefix table", 2) end if type(step) ~= 'number' then error("Invalid step value detected", 2) end -- Get arguments without a number suffix, and check for bad input. for i,v in ipairs(prefixTable) do if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then error('Invalid input detected to preprocessArgs prefix table', 2) end preprocessSingleArg(v.prefix) -- Only parse the depend parameter if the prefix parameter is present and not blank. if args[v.prefix] and v.depend then for j, dependValue in ipairs(v.depend) do if type(dependValue) ~= 'string' then error('Invalid "depend" parameter value detected in preprocessArgs') end preprocessSingleArg(dependValue) end end end -- Get arguments with number suffixes. local a = 1 -- Counter variable. local moreArgumentsExist = true while moreArgumentsExist == true do moreArgumentsExist = false for i = a, a + step - 1 do for j,v in ipairs(prefixTable) do local prefixArgName = v.prefix .. tostring(i) if origArgs[prefixArgName] then moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones. preprocessSingleArg(prefixArgName) end -- Process the depend table if the prefix argument is present and not blank, or -- we are processing "prefix1" and "prefix" is present and not blank, and -- if the depend table is present. if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then for j,dependValue in ipairs(v.depend) do local dependArgName = dependValue .. tostring(i) preprocessSingleArg(dependArgName) end end end end a = a + step end end function p.infobox(frame) -- If called via #invoke, use the args passed into the invoking template. -- Otherwise, for testing purposes, assume args are being passed directly in. if frame == mw.getCurrentFrame() then origArgs = frame:getParent().args else origArgs = frame end -- Parse the data parameters in the same order that the old {{infobox}} did, so that -- references etc. will display in the expected places. Parameters that depend on -- another parameter are only processed if that parameter is present, to avoid -- phantom references appearing in article reference lists. preprocessSingleArg('child') preprocessSingleArg('bodyclass') preprocessSingleArg('subbox') preprocessSingleArg('bodystyle') preprocessSingleArg('title') preprocessSingleArg('titleclass') preprocessSingleArg('titlestyle') preprocessSingleArg('above') preprocessSingleArg('aboveclass') preprocessSingleArg('abovestyle') preprocessArgs({ {prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}} }, 10) preprocessSingleArg('subheaderstyle') preprocessSingleArg('subheaderclass') preprocessArgs({ {prefix = 'image', depend = {'caption', 'imagerowclass'}} }, 10) preprocessSingleArg('captionstyle') preprocessSingleArg('imagestyle') preprocessSingleArg('imageclass') preprocessArgs({ {prefix = 'header'}, {prefix = 'data', depend = {'label'}}, {prefix = 'rowclass'}, {prefix = 'rowstyle'}, {prefix = 'rowcellstyle'}, {prefix = 'class'}, {prefix = 'dataid'}, {prefix = 'labelid'}, {prefix = 'headerid'}, {prefix = 'rowid'} }, 50) preprocessSingleArg('headerclass') preprocessSingleArg('headerstyle') preprocessSingleArg('labelstyle') preprocessSingleArg('datastyle') preprocessSingleArg('below') preprocessSingleArg('belowclass') preprocessSingleArg('belowstyle') preprocessSingleArg('name') args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent preprocessSingleArg('decat') return _infobox() end return p 2e046db27a7f61675131debae5a131a9dee12195 Template:T 10 59 117 116 2024-01-11T08:38:19Z EvaTheServal 2 1 revision imported wikitext text/x-wiki <includeonly><nowiki>{{</nowiki>[[Template:{{{1}}}|{{{1}}}]]{{t/piece|{{{2|---}}}}}{{t/piece|{{{3|---}}}}}{{t/piece|{{{4|---}}}}}{{t/piece|{{{5|---}}}}}{{t/piece|{{{6|---}}}}}{{t/piece|{{{7|---}}}}}{{t/piece|{{{8|---}}}}}{{t/piece|{{{9|---}}}}}{{t/piece|{{{10|---}}}}}{{t/piece|{{{11|---}}}}}{{t/piece|{{{12|---}}}}}{{t/piece|{{{13|---}}}}}{{t/piece|{{{14|---}}}}}{{t/piece|{{{15|---}}}}}{{t/piece|{{{16|---}}}}}{{t/piece|{{{17|---}}}}}{{t/piece|{{{18|---}}}}}{{t/piece|{{{19|---}}}}}{{t/piece|{{{20|---}}}}}{{t/piece|{{{21|---}}}}}<nowiki>}}</nowiki></includeonly><noinclude> {{documentation}}</noinclude> 9bbfbb3d891ffa62ccebed3d5790ccf39d59c793 Template:T/piece 10 60 119 118 2024-01-11T08:38:20Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{#ifeq: {{{1|---}}}|---||&#124;<font color="gray">''&lt;{{{1}}}&gt;''</font>}}<noinclude> {{/doc}}</noinclude> 2ddf7df2334b2a1624bf213ade67ba6b68296e86 Template:Infobox/doc 10 61 121 120 2024-01-11T08:38:20Z EvaTheServal 2 1 revision imported wikitext text/x-wiki {{Documentation|fromWikipedia=true}} <!-- EDIT TEMPLATE DOCUMENTATION BELOW THIS LINE --> Please refer to {{t|Infobox}} on Wikipedia for more details <noinclude></noinclude> <includeonly> <!-- Template catergories go here --> [[Category:Infobox templates]] </includeonly> 04b27574c3656318415ace03777bcc2a3c16ef74 Module:Array 828 62 123 122 2024-01-11T08:38:22Z EvaTheServal 2 1 revision imported Scribunto text/plain -- Imported from: https://runescape.wiki/w/Module:Array local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local checkTypeMulti = libraryUtil.checkTypeMulti ---@class Array ---@operator call(any[]): Array ---@operator concat(any[]): Array ---@operator concat(number|string|function): string ---@operator unm: Array ---@operator add(number|number[]|Array): Array ---@operator sub(number|number[]|Array): Array ---@operator mul(number|number[]|Array): Array ---@operator div(number|number[]|Array): Array ---@operator pow(number|number[]|Array): Array local Array = { pop = table.remove } Array.__index = Array setmetatable(Array, { __index = table, __call = function (_, arr) return Array.new(arr) end }) -- function Array.__tostring(arr) -- -- local dumpObject = require('Module:Logger').dumpObject -- require 'log' -- local dumpObject = dumpObject -- local mt = getmetatable(arr) -- setmetatable(arr, nil) -- local str = dumpObject(arr, {clean=true, collapseLimit=100}) -- setmetatable(arr, mt) -- return str -- end function Array.__concat(lhs, rhs) if type(lhs) == 'table' and type(rhs) == 'table' then local res = {} for i = 1, #lhs do res[i] = lhs[i] end local l = #lhs for i = 1, #rhs do res[i + l] = rhs[i] end return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) else return tostring(lhs) .. tostring(rhs) end end function Array.__unm(arr) return Array.map(arr, function(x) return -x end) end ---@param lhs number|number[]|Array ---@param rhs number|number[]|Array ---@param funName string ---@param opName string ---@param fun fun(lhs: number, rhs: number): number ---@return Array local function mathTemplate(lhs, rhs, funName, opName, fun) checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'}) checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'}) local res = {} if type(lhs) == 'number' then for i = 1, #rhs do res[i] = fun(lhs, rhs[i]) end elseif type(rhs) == 'number' then for i = 1, #lhs do res[i] = fun(lhs[i], rhs) end else assert(#lhs == #rhs, string.format('Elementwise %s failed because arrays have different sizes (left: %d, right: %d)', opName, #lhs, #rhs)) for i = 1, #lhs do res[i] = fun(lhs[i], rhs[i]) end end return setmetatable(res, getmetatable(lhs) or getmetatable(rhs)) end function Array.__add(lhs, rhs) return mathTemplate(lhs, rhs, '__add', 'addition', function(x, y) return x + y end) end function Array.__sub(lhs, rhs) return mathTemplate(lhs, rhs, '__sub', 'substraction', function(x, y) return x - y end) end function Array.__mul(lhs, rhs) return mathTemplate(lhs, rhs, '__mul', 'multiplication', function(x, y) return x * y end) end function Array.__div(lhs, rhs) return mathTemplate(lhs, rhs, '__div', 'division', function(x, y) return x / y end) end function Array.__pow(lhs, rhs) return mathTemplate(lhs, rhs, '__pow', 'exponentiation', function(x, y) return x ^ y end) end function Array.__eq(lhs, rhs) if #lhs ~= #rhs then return false end for i = 1, #lhs do if lhs[i] ~= rhs[i] then return false end end return true end ---Behaviour depends on the value of `fn`: ---* `nil` - Checks that the array doesn't contain any **false** elements. ---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for every element. ---* `number` | `table` | `boolean` - Checks that all elements in `arr` are equal to this value. ---@param arr any[] ---@param fn? any ---@return boolean function Array.all(arr, fn) checkType('Module:Array.all', 1, arr, 'table') if fn == nil then fn = function(item) return item end end if type(fn) ~= 'function' then local val = fn fn = function(item) return item == val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if not fn(arr[i], i) then return false end i = i + 1 end return true end ---Behaviour depends on the value of `fn`: ---* `nil` - Checks that the array contains at least one non **false** element. ---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for at least one element. ---* `number` | `table` | `boolean` - Checks that `arr` contains this value. ---@param arr any[] ---@param fn? any ---@return boolean function Array.any(arr, fn) checkType('Module:Array.any', 1, arr, 'table') if fn == nil then fn = function(item) return item end end if type(fn) ~= 'function' then local val = fn fn = function(item) return item == val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if fn(arr[i], i) then return true end i = i + 1 end return false end ---Recursively removes all metatables. ---@param arr any[] ---@return any[] function Array.clean(arr) checkType('Module:Array.clean', 1, arr, 'table') for i = 1, #arr do if type(arr[i]) == 'table' then Array.clean(arr[i]) end end setmetatable(arr, nil) return arr end ---Make a copy of the input table. Preserves metatables. ---@generic T: any[] ---@param arr T ---@param deep? boolean # Recursively clone subtables if **true**. ---@return T function Array.clone(arr, deep) checkType('Module:Array.clone', 1, arr, 'table') checkType('Module:Array.clone', 2, deep, 'boolean', true) local res = {} for i = 1, #arr do if deep == true and type(arr[i]) == 'table' then res[i] = Array.clone(arr[i], true) else res[i] = arr[i] end end return setmetatable(res, getmetatable(arr)) end ---Check if `arr` contains `val`. ---@param arr any[] ---@param val any ---@return boolean function Array.contains(arr, val) checkType('Module:Array.contains', 1, arr, 'table') for i = 1, #arr do if arr[i] == val then return true end end return false end ---Check if `arr` contains any of the values in the table `t`. ---@param arr any[] ---@param t any[] ---@return boolean function Array.containsAny(arr, t) checkType('Module:Array.containsAny', 1, arr, 'table') checkType('Module:Array.containsAny', 2, t, 'table') local lookupTbl = {} for i = 1, #t do lookupTbl[t[i]] = true end for i = 1, #arr do if lookupTbl[arr[i]] then return true end end return false end ---Check if `arr` contains all values in the table `t`. ---@param arr any[] ---@param t any[] ---@return boolean function Array.containsAll(arr, t) checkType('Module:Array.containsAll', 1, arr, 'table') checkType('Module:Array.containsAll', 2, t, 'table') local lookupTbl = {} local l = #t local trueCount = 0 for i = 1, l do lookupTbl[t[i]] = false end for i = 1, #arr do if lookupTbl[arr[i]] == false then lookupTbl[arr[i]] = true trueCount = trueCount + 1 end if trueCount == l then return true end end return false end ---Convolute two number arrays. ---@generic T: number[] ---@param x T ---@param y T ---@return T function Array.convolve(x, y) checkType('Module:Array.convolve', 1, x, 'table') checkType('Module:Array.convolve', 2, y, 'table') local z = {} local xLen, yLen = #x, #y for j = 1, (xLen + yLen - 1) do local sum = 0 for k = math.max(1, j - yLen + 1), math.min(xLen, j) do sum = sum + x[k] * y[j-k+1] end z[j] = sum end return setmetatable(z, getmetatable(x) or getmetatable(y)) end ---Remove **nil** values from `arr` while preserving order. ---@generic T: any[] ---@param arr T ---@return T function Array.condenseSparse(arr) checkType('Module:Array.condenseSparse', 1, arr, 'table') local keys = {} local res = {} local l = 0 for k in pairs(arr) do l = l + 1 keys[l] = k end table.sort(keys) for i = 1, l do res[i] = arr[keys[i]] end return setmetatable(res, getmetatable(arr)) end ---Behaviour depends on value of `val`: ---* `nil` - Counts the number of non **false** elements. ---* `fun(elem: any): boolean` - Count the number of times the function returned **true**. ---* `boolean` | `number` | `table` - Counts the number of times this value occurs in `arr`. ---@param arr any[] ---@param val? any ---@return integer function Array.count(arr, val) checkType('Module:Array.count', 1, arr, 'table') if val == nil then val = function(item) return item end end if type(val) ~= 'function' then local _val = val val = function(item) return item == _val end end local count = 0 for i = 1, #arr do if val(arr[i]) then count = count + 1 end end return count end ---Differentiate the array ---@generic T: number[] ---@param arr T ---@param order number? # Oder of the differentiation. Default is 1. ---@return T # Length is `#arr - order` function Array.diff(arr, order) checkType('Module:Array.diff', 1, arr, 'table') checkType('Module:Array.diff', 2, order, 'number', true) local res = {} for i = 1, #arr - 1 do res[i] = arr[i+1] - arr[i] end if order and order > 1 then return Array.diff(res, order - 1) end return setmetatable(res, getmetatable(arr)) end ---Loops over `arr` and passes each element as the first argument to `fn`. This function returns nothing. ---@param arr any[] ---@param fn fun(elem: any, i?: integer) function Array.each(arr, fn) checkType('Module:Array.each', 1, arr, 'table') checkType('Module:Array.each', 2, fn, 'function') local i = 1 while arr[i] ~= nil do fn(arr[i], i) i = i + 1 end end ---Makes a copy of `arr` with only elements for which `fn` returned **true**. ---@generic T: any[] ---@param arr T ---@param fn fun(elem: any, i?: integer): boolean ---@return T function Array.filter(arr, fn) checkType('Module:Array.filter', 1, arr, 'table') checkType('Module:Array.filter', 2, fn, 'function') local r = {} local len = 0 local i = 1 while arr[i] ~= nil do if fn(arr[i], i) then len = len + 1 r[len] = arr[i] end i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Find the first elements for which `fn` returns **true**. ---@param arr any[] ---@param fn any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`. ---@param default? any # Value to return if no element passes the test. ---@return any? elem # The first element that passed the test. ---@return integer? i # The index of the item that passed the test. function Array.find(arr, fn, default) checkType('Module:Array.find', 1, arr, 'table') checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'}) if type(fn) ~= 'function' then local _val = fn fn = function(item) return item == _val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if fn(arr[i], i) then return arr[i], i end i = i + 1 end return default, nil end ---Find the index of `val`. ---@param arr any[] ---@param val any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`. ---@param default? any # Value to return if no element passes the test. ---@return integer? function Array.find_index(arr, val, default) checkType('Module:Array.find_index', 1, arr, 'table') checkTypeMulti('Module:Array.find_index', 2, val, {'function', 'table', 'number', 'boolean'}) if type(val) ~= 'function' then local _val = val val = function(item) return item == _val end end local i = 1 while arr[i] ~= nil do ---@diagnostic disable-next-line: redundant-parameter if val(arr[i], i) then return i end i = i + 1 end return default end ---Extracts a subset of `arr`. ---@generic T: any[] ---@param arr T ---@param indexes integer|integer[] # Indexes of the elements. ---@return T function Array.get(arr, indexes) checkType('Module:Array.set', 1, arr, 'table') checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'}) if type(indexes) == 'number' then indexes = {indexes} end local res = {} for i = 1, #indexes do res[i] = arr[indexes[i]] end return setmetatable(res, getmetatable(arr)) end ---Integrates the array. Effectively does $\left\{\sum^{n}_{start}{arr[n]} \,\Bigg|\, n \in [start, stop]\right\}$. ---@generic T: number[] ---@param arr T # number[] ---@param start? integer # Index where to start the summation. Defaults to 1. ---@param stop? integer # Index where to stop the summation. Defaults to #arr. ---@return T function Array.int(arr, start, stop) checkType('Module:Array.int', 1, arr, 'table') checkType('Module:Array.int', 2, start, 'number', true) checkType('Module:Array.int', 3, stop, 'number', true) local res = {} start = start or 1 stop = stop or #arr res[1] = arr[start] for i = 1, stop - start do res[i+1] = res[i] + arr[start + i] end return setmetatable(res, getmetatable(arr)) end ---Returns an array with elements that are present in both tables. ---@generic T: any[] ---@param arr1 T ---@param arr2 T ---@return T function Array.intersect(arr1, arr2) checkType('Module:Array.intersect', 1, arr1, 'table') checkType('Module:Array.intersect', 2, arr2, 'table') local arr2Elements = {} local res = {} local len = 0 Array.each(arr2, function(item) arr2Elements[item] = true end) Array.each(arr1, function(item) if arr2Elements[item] then len = len + 1 res[len] = item end end) return setmetatable(res, getmetatable(arr1) or getmetatable(arr2)) end ---Checks if the two inputs have at least one element in common. ---@param arr1 any[] ---@param arr2 any[] ---@return boolean function Array.intersects(arr1, arr2) checkType('Module:Array.intersects', 1, arr1, 'table') checkType('Module:Array.intersects', 2, arr2, 'table') local small = {} local large if #arr1 <= #arr2 then Array.each(arr1, function(item) small[item] = true end) large = arr2 else Array.each(arr2, function(item) small[item] = true end) large = arr1 end return Array.any(large, function(item) return small[item] end) end ---Inserts values into `arr`. ---@generic T: any[] ---@param arr T ---@param val any # If `val` is an array and `unpackVal` is **true** then the individual elements of `val` are inserted. ---@param index? integer # Location to start the insertion. Default is at the end of `arr`. ---@param unpackVal? boolean # Default is **false**. ---@return T ---@overload fun(arr: T, val: any, unpackVal: boolean): T function Array.insert(arr, val, index, unpackVal) checkType('Module:Array.insert', 1, arr, 'table') checkTypeMulti('Module:Array.insert', 3, index, {'number', 'boolean', 'nil'}) checkType('Module:Array.insert', 4, unpackVal, 'boolean', true) if type(index) == 'boolean' then unpackVal, index = index, nil end local len = #arr index = index or (len + 1) local mt = getmetatable(arr) setmetatable(arr, nil) if type(val) == 'table' and unpackVal then local len2 = #val for i = 0, len - index do arr[len + len2 - i] = arr[len - i] end for i = 0, len2 - 1 do arr[index + i] = val[i + 1] end else table.insert(arr, index, val) end return setmetatable(arr, mt) end ---Returns the last element of `arr`. ---@param arr any[] ---@param offset? integer ---@return any function Array.last(arr, offset) checkType('Module:Array.last', 1, arr, 'table') checkType('Module:Array.last', 2, offset, 'number', true) return arr[#arr + offset] end ---Returns a new table were each element of `arr` is modified by `fn`. ---@generic T: any[] ---@param arr T ---@param fn fun(elem: any, i?: integer): any # First argument is the current element, the second argument is the index of the current element. ---@return T function Array.map(arr, fn) checkType('Module:Array.map', 1, arr, 'table') checkType('Module:Array.map', 2, fn, 'function') local len = 0 local r = {} local i = 1 while arr[i] ~= nil do local tmp = fn(arr[i], i) if tmp ~= nil then len = len + 1 r[len] = tmp end i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Find the element for which `fn` returned the largest value. ---@param arr any[] ---@param fn fun(elem: any): any # The returned value needs to be comparable using the `<` operator. ---@return any elem # The element with the largest `fn` value. ---@return integer i # The index of this element. function Array.max_by(arr, fn) checkType('Module:Array.max_by', 1, arr, 'table') checkType('Module:Array.max_by', 2, fn, 'function') return unpack(Array.reduce(arr, function(new, old, i) local y = fn(new) return y > old[2] and {new, y, i} or old end, {nil, -math.huge})) end ---Find the largest value in the array. ---@param arr any[] # The values need to be comparable using the `<` operator. ---@return any elem ---@return integer i # The index of the largest value. function Array.max(arr) checkType('Module:Array.max', 1, arr, 'table') local val, _, i = Array.max_by(arr, function(x) return x end) return val, i end ---Find the smallest value in the array. ---@param arr any[] # The values need to be comparable using the `<` operator. ---@return any elem ---@return integer i # The index of the smallest value. function Array.min(arr) checkType('Module:Array.min', 1, arr, 'table') local val, _, i = Array.max_by(arr, function(x) return -x end) return val, i end ---Turn the input table into an Array. This makes it possible to use the colon `:` operator to access the Array methods. --- ---It also enables the use of math operators with the array. ---``` ---local x = arr.new{ 1, 2, 3 } ---local y = arr{ 4, 5, 6 } -- Alternative notation --- ---print( -x ) --> { -1, -2, -3 } ---print( x + 2 ) --> { 3, 4, 5 } ---print( x - 2 ) --> { -1, 0, 1 } ---print( x * 2 ) --> { 2, 4, 6 } ---print( x / 2 ) --> { 0.5, 1, 1.5 } ---print( x ^ 2 ) --> { 1, 4, 9 } --- ---print( x + y ) --> { 5, 7, 9 } ---print( x .. y ) --> { 1, 2, 3, 4, 5, 6 } ---print( (x .. y):reject{3, 4, 5} ) --> { 1, 2, 6 } ---print( x:sum() ) --> 6 --- ---print( x:update( {1, 3}, y:get{2, 3} * 2 ) ) --> { 10, 2, 12 } ---``` ---@param arr? any[] ---@return Array function Array.new(arr) local obj = arr or {} for _, v in pairs(obj) do if type(v) == 'table' then Array.new(v) end end if getmetatable(obj) == nil then setmetatable(obj, Array) end return obj end ---Creates an object that returns a value that is `step` higher than the previous value each time it gets called. --- ---The stored value can be read without incrementing by reading the `val` field. --- ---A new stored value can be set through the `val` field. --- ---A new step size can be set through the `step` field. ---``` ---local inc = arr.newIncrementor(10, 5) ---print( inc() ) --> 10 ---print( inc() ) --> 15 ---print( inc.val ) --> 15 ---inc.val = 100 ---inc.step = 20 ---print( inc.val ) --> 100 ---print( inc() ) --> 120 ---``` ---@param start? number # Default is 1. ---@param step? number # Default is 1. ---@return Incrementor function Array.newIncrementor(start, step) checkType('Module:Array.newIncrementor', 1, start, 'number', true) checkType('Module:Array.newIncrementor', 2, step, 'number', true) step = step or 1 local n = (start or 1) - step ---@class Incrementor local obj = {} return setmetatable(obj, { __call = function() n = n + step return n end, __tostring = function() return n end, __index = function() return n end, __newindex = function(self, k, v) if k == 'step' and type(v) == 'number' then step = v elseif type(v) == 'number' then n = v end end, __concat = function(x, y) return tostring(x) .. tostring(y) end }) end ---Returns a range of numbers. ---@param start number # Start value inclusive. ---@param stop number # Stop value inclusive for integers, exclusive for floats. ---@param step? number # Default is 1. ---@return Array ---@overload fun(stop: number): Array function Array.range(start, stop, step) checkType('Module:Array.range', 1, start, 'number') checkType('Module:Array.range', 2, stop, 'number', true) checkType('Module:Array.range', 3, step, 'number', true) local arr = {} local len = 0 if not stop then stop = start start = 1 end for i = start, stop, step or 1 do len = len + 1 arr[len] = i end return setmetatable(arr, Array) end ---Condenses the array into a single value. --- ---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element. --- ---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element. ---``` ---local t = { 1, 2, 3, 4 } ---local sum = arr.reduce( t, function(elem, acc) return acc + elem end ) -- sum == 10 ---``` ---@param arr any[] ---@param fn fun(elem: any, acc: any, i?: integer): any # The result of this function becomes the `acc` for the next element. ---@param accumulator? any ---@return any # This is the last accumulator value. function Array.reduce(arr, fn, accumulator) checkType('Module:Array.reduce', 1, arr, 'table') checkType('Module:Array.reduce', 2, fn, 'function') local acc = accumulator local i = 1 if acc == nil then acc = arr[1] i = 2 end while arr[i] ~= nil do acc = fn(arr[i], acc, i) i = i + 1 end return acc end ---Make a copy off `arr` with certain values removed. --- ---Behaviour for different values of `val`: ---* `boolean` | `number` - Remove values equal to this. ---* `table` - Remove all values in this table. ---* `fun(elem: any, i?: integer): boolean` - Remove elements for which the functions returns **true**. ---@generic T: any[] ---@param arr T ---@param val table|function|number|boolean ---@return T function Array.reject(arr, val) checkType('Module:Array.reject', 1, arr, 'table') checkTypeMulti('Module:Array.reject', 2, val, {'function', 'table', 'number', 'boolean'}) if type(val) ~= 'function' and type(val) ~= 'table' then val = {val} end local r = {} local len = 0 if type(val) == 'function' then local i = 1 while arr[i] ~= nil do if not val(arr[i], i) then len = len + 1 r[len] = arr[i] end i = i + 1 end else local rejectMap = {} Array.each(val --[[@as any[] ]], function(item) rejectMap[item] = true end) local i = 1 while arr[i] ~= nil do if not rejectMap[arr[i]] then len = len + 1 r[len] = arr[i] end i = i + 1 end end return setmetatable(r, getmetatable(arr)) end ---Returns an Array with `val` repeated `n` times. ---@param val any ---@param n integer ---@return Array function Array.rep(val, n) checkType('Module:Array.rep', 2, n, 'number') local r = {} for i = 1, n do r[i] = val end return setmetatable(r, Array) end ---Condenses the array into a single value while saving every accumulator value. --- ---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element. --- ---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element. ---``` ---local t = { 1, 2, 3, 4 } ---local x = arr.scan( t, function(elem, acc) return acc + elem end ) -- x = { 1, 3, 6, 10 } ---``` ---@generic T: any[] ---@param arr T ---@param fn fun(elem: any, acc: any, i?: integer): any # Returned value becomes the accumulator for the next element. ---@param accumulator? any ---@return T function Array.scan(arr, fn, accumulator) checkType('Module:Array.scan', 1, arr, 'table') checkType('Module:Array.scan', 2, fn, 'function') local acc = accumulator local r = {} local i = 1 while arr[i] ~= nil do if i == 1 and not accumulator then acc = arr[i] else acc = fn(arr[i], acc, i) end r[i] = acc i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Update a range of index with a range of values. --- ---If if only one value is given but multiple indexes than that value is set for all those indexes. --- ---If `values` is a table then it must of the same length as `indexes`. ---@generic T: any[] ---@param arr T ---@param indexes integer|integer[] ---@param values any|any[] ---@return T function Array.set(arr, indexes, values) checkType('Module:Array.set', 1, arr, 'table') checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'}) local mt = getmetatable(arr) setmetatable(arr, nil) if type(indexes) == 'number' then indexes = {indexes} end if type(values) == 'table' then assert(#indexes == #values, string.format("Module:Array.set: 'indexes' and 'values' arrays are not equal length (#indexes = %d, #values = %d)", #indexes, #values)) for i = 1, #indexes do arr[indexes[i]] = values[i] end else for i = 1, #indexes do arr[indexes[i]] = values end end return setmetatable(arr, mt) end ---Extract a subtable from `arr`. ---@generic T: any[] ---@param arr T ---@param start integer # Start index. Use negative values to count form the end of the array. ---@param stop integer # Stop index. Use negative values to count form the end of the array. ---@return T ---@overload fun(arr: T, stop: integer): T function Array.slice(arr, start, stop) checkType('Module:Array.slice', 1, arr, 'table') checkType('Module:Array.slice', 2, start, 'number', true) checkType('Module:Array.slice', 3, stop, 'number', true) start = start or #arr if start < 0 then start = #arr + start end if stop == nil then stop = start start = 1 end if stop < 0 then stop = #arr + stop end local r = {} local len = 0 for i = start, stop do len = len + 1 r[len] = arr[i] end return setmetatable(r, getmetatable(arr)) end ---Split `arr` into two arrays. ---@generic T: any[] ---@param arr T ---@param index integer # Index to split on. ---@return T x # [1, index] ---@return T y # [index + 1, #arr] function Array.split(arr, index) checkType('Module:Array.split', 1, arr, 'table') checkType('Module:Array.split', 2, index, 'number') local x = {} local y = {} for i = 1, #arr do table.insert(i <= index and x or y, arr[i]) end return setmetatable(x, getmetatable(arr)), setmetatable(y, getmetatable(arr)) end ---Returns the sum of all elements of `arr`. ---@param arr number[] ---@return number function Array.sum(arr) checkType('Module:Array.sum', 1, arr, 'table') local res = 0 for i = 1, #arr do res = res + arr[i] end return res end ---Extract a subtable from `arr`. ---@generic T: any[] ---@param arr T ---@param count integer # Length of the subtable. ---@param start? integer # Start index. Default is 1. ---@return T function Array.take(arr, count, start) checkType('Module:Array.take', 1, arr, 'table') checkType('Module:Array.take', 2, count, 'number') checkType('Module:Array.take', 3, start, 'number', true) local x = {} start = start or 1 for i = start, math.min(#arr, count + start - 1) do table.insert(x, arr[i]) end return setmetatable(x, getmetatable(arr)) end ---Extract a subtable from `arr`. ---``` ---local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ---local x = arr.take_every( t, 2 ) --> x = { 1, 3, 5, 7, 9 } ---local x = arr.take_every( t, 2, 3 ) --> x = { 1, 3, 5 } ---local x = arr.take_every( t, 2, 3, 2 ) --> x = { 2, 4, 6 } --- ``` ---@generic T: any[] ---@param arr T ---@param n integer # Step size. ---@param start? integer # Start index. ---@param count? integer # Max amount of elements to get. ---@return T function Array.take_every(arr, n, start, count) checkType('Module:Array.take_every', 1, arr, 'table') checkType('Module:Array.take_every', 2, n, 'number') checkType('Module:Array.take_every', 3, start, 'number', true) checkType('Module:Array.take_every', 4, count, 'number', true) count = count or #arr local r = {} local len = 0 local i = start or 1 while arr[i] ~= nil and len < count do len = len + 1 r[len] = arr[i] i = i + n end return setmetatable(r, getmetatable(arr)) end ---Return a new table with all duplicates removed. ---@generic T: any[] ---@param arr T ---@param fn? fun(elem: any): any # Function to generate an id for each element. The result will then contain elements that generated unique ids. ---@return T function Array.unique(arr, fn) checkType('Module:Array.unique', 1, arr, 'table') checkType('Module:Array.unique', 2, fn, 'function', true) fn = fn or function(item) return item end local r = {} local len = 0 local hash = {} local i = 1 while arr[i] ~= nil do local id = fn(arr[i]) if not hash[id] then len = len + 1 r[len] = arr[i] hash[id] = true end i = i + 1 end return setmetatable(r, getmetatable(arr)) end ---Combine elements with the same index from multiple arrays. ---``` ---local x = {1, 2, 3} ---local y = {4, 5, 6, 7} ---local z = arr.zip( x, y ) --> z = { { 1, 4 }, { 2, 5 }, { 3, 6 }, { 7 } } ---``` ---@param ... any[] ---@return Array function Array.zip(...) local arrs = { ... } checkType('Module:Array.zip', 1, arrs[1], 'table') local r = {} local _, longest = Array.max_by(arrs, function(arr) return #arr end) for i = 1, longest do local q = {} for j = 1, #arrs do table.insert(q, arrs[j][i]) end table.insert(r, setmetatable(q, Array)) end return setmetatable(r, Array) end -- Range indexing has a performance impact so this is placed in a separate subclass Array.RI_mt = {} for k, v in pairs(Array) do Array.RI_mt[k] = v end function Array.RI_mt.__index(t, k) if type(k) == 'table' then local res = {} for i = 1, #k do res[i] = t[k[i]] end return setmetatable(res, Array) else return Array[k] end end function Array.RI_mt.__newindex(t, k, v) if type(k) == 'table' then if type(v) == 'table' then for i = 1, #k do t[k[i]] = v[i] end else for i = 1, #k do t[k[i]] = v end end else rawset(t, k, v) end end ---Enable range indexing on the input array. --- ---This has a performance impact on reads and writes to the table. ---``` ---local t = arr{10, 11, 12, 13, 14, 15}:ri() ---print( t[{2, 3}] ) --> { 11, 12 } ---``` ---@param arr any[] ---@param recursive? boolean # Default is false. ---@return Array function Array.ri(arr, recursive) checkType('Module:Array.ri', 1, arr, 'table') checkType('Module:Array.ri', 2, recursive, 'boolean', true) arr = arr or {} if recursive then for _, v in pairs(arr) do if type(v) == 'table' then Array.ri(v, true) end end end if getmetatable(arr) == nil or getmetatable(arr) == Array then setmetatable(arr, Array.RI_mt) end return arr end ---Globally enable range indexing on all Array objects by default. ---@param set boolean function Array.allwaysAllowRangeIndexing(set) checkType('Module:Array.allwaysAllowRangeIndexing', 1, set, 'boolean') if set then Array.__index = Array.RI_mt.__index Array.__newindex = Array.RI_mt.__newindex else Array.__index = Array Array.__newindex = nil end end return Array c81adb59b4d3a4728952df3ad8d681664333a799 Module:Format link 828 63 125 124 2024-01-11T08:38:23Z EvaTheServal 2 1 revision imported Scribunto text/plain -- Imported from: https://en.wikipedia.org/wiki/Module:Format_link -------------------------------------------------------------------------------- -- Format link -- -- Makes a wikilink from the given link and display values. Links are escaped -- with colons if necessary, and links to sections are detected and displayed -- with " § " as a separator rather than the standard MediaWiki "#". Used in -- the {{format link}} template. -------------------------------------------------------------------------------- local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg local mArguments -- lazily initialise [[Module:Arguments]] local mError -- lazily initialise [[Module:Error]] local yesno -- lazily initialise [[Module:Yesno]] local p = {} -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function getArgs(frame) -- Fetches the arguments from the parent frame. Whitespace is trimmed and -- blanks are removed. mArguments = require('Module:Arguments') return mArguments.getArgs(frame, {parentOnly = true}) end local function removeInitialColon(s) -- Removes the initial colon from a string, if present. return s:match('^:?(.*)') end local function maybeItalicize(s, shouldItalicize) -- Italicize s if s is a string and the shouldItalicize parameter is true. if s and shouldItalicize then return '<i>' .. s .. '</i>' else return s end end local function parseLink(link) -- Parse a link and return a table with the link's components. -- These components are: -- - link: the link, stripped of any initial colon (always present) -- - page: the page name (always present) -- - section: the page name (may be nil) -- - display: the display text, if manually entered after a pipe (may be nil) link = removeInitialColon(link) -- Find whether a faux display value has been added with the {{!}} magic -- word. local prePipe, display = link:match('^(.-)|(.*)$') link = prePipe or link -- Find the page, if it exists. -- For links like [[#Bar]], the page will be nil. local preHash, postHash = link:match('^(.-)#(.*)$') local page if not preHash then -- We have a link like [[Foo]]. page = link elseif preHash ~= '' then -- We have a link like [[Foo#Bar]]. page = preHash end -- Find the section, if it exists. local section if postHash and postHash ~= '' then section = postHash end return { link = link, page = page, section = section, display = display, } end local function formatDisplay(parsed, options) -- Formats a display string based on a parsed link table (matching the -- output of parseLink) and an options table (matching the input options for -- _formatLink). local page = maybeItalicize(parsed.page, options.italicizePage) local section = maybeItalicize(parsed.section, options.italicizeSection) if (not section) then return page elseif (not page) then return mw.ustring.format('§&nbsp;%s', section) else return mw.ustring.format('%s §&nbsp;%s', page, section) end end local function missingArgError(target) mError = require('Module:Error') return mError.error{message = 'Error: no link or target specified! ([[' .. target .. '#Errors|help]])' } end -------------------------------------------------------------------------------- -- Main functions -------------------------------------------------------------------------------- function p.formatLink(frame) -- The formatLink export function, for use in templates. yesno = require('Module:Yesno') local args = getArgs(frame) local link = args[1] or args.link local target = args[3] or args.target if not (link or target) then return missingArgError('Template:Format link') end return p._formatLink{ link = link, display = args[2] or args.display, target = target, italicizePage = yesno(args.italicizepage), italicizeSection = yesno(args.italicizesection), categorizeMissing = args.categorizemissing } end function p._formatLink(options) -- The formatLink export function, for use in modules. checkType('_formatLink', 1, options, 'table') local function check(key, expectedType) --for brevity checkTypeForNamedArg( '_formatLink', key, options[key], expectedType or 'string', true ) end check('link') check('display') check('target') check('italicizePage', 'boolean') check('italicizeSection', 'boolean') check('categorizeMissing') -- Normalize link and target and check that at least one is present if options.link == '' then options.link = nil end if options.target == '' then options.target = nil end if not (options.link or options.target) then return missingArgError('Module:Format link') end local parsed = parseLink(options.link) local display = options.display or parsed.display local catMissing = options.categorizeMissing local category = '' -- Find the display text if not display then display = formatDisplay(parsed, options) end -- Handle the target option if present if options.target then local parsedTarget = parseLink(options.target) parsed.link = parsedTarget.link parsed.page = parsedTarget.page end -- Test if page exists if a diagnostic category is specified if catMissing and (mw.ustring.len(catMissing) > 0) then local title = nil if parsed.page then title = mw.title.new(parsed.page) end if title and (not title.isExternal) then local success, exists = pcall(function() return title.exists end) if success and not exists then category = mw.ustring.format('[[Category:%s]]', catMissing) end end end -- Format the result as a link if parsed.link == display then return mw.ustring.format('[[:%s]]%s', parsed.link, category) else return mw.ustring.format('[[:%s|%s]]%s', parsed.link, display, category) end end -------------------------------------------------------------------------------- -- Derived convenience functions -------------------------------------------------------------------------------- function p.formatPages(options, pages) -- Formats an array of pages using formatLink and the given options table, -- and returns it as an array. Nil values are not allowed. local ret = {} for i, page in ipairs(pages) do ret[i] = p._formatLink{ link = page, categorizeMissing = options.categorizeMissing, italicizePage = options.italicizePage, italicizeSection = options.italicizeSection } end return ret end return p 410e1254e813fed6fe2f04598836316a197db2d1 Module:Infobox/styles.css 828 64 127 126 2024-01-11T08:38:24Z EvaTheServal 2 1 revision imported text text/plain .infobox { /* In case if tooltips go out of boundary */ overflow: visible; width: 100%; max-width: 400px; margin-top: 0; margin-bottom: var( --space-md ); background: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); border-spacing: 0; font-size: 0.875rem; text-align: left; display: block; } /* Table elements */ .infobox tbody { display: flex; flex-wrap: wrap; } .infobox tr { display: flex; box-sizing: border-box; flex-direction: column; padding: 0 10px; margin-top: 10px; } .infobox th, .infobox td { padding: 0 5px; } /* Infobox column */ .infobox .infobox-nocol { width: 100%; flex-direction: row; } .infobox .infobox-nocol th { width: 30%; } .infobox .infobox-nocol td { width: 70%; } .infobox .infobox-col1 { width: 100%; } .infobox .infobox-col2 { width: 50%; } .infobox .infobox-col3 { width: calc( 100% / 3 ); } .infobox .infobox-col4 { width: 25%; } .infobox-data { min-width: 25%; } /* Infobox image */ .infobox .infobox-image { overflow: hidden; padding: 0; margin-top: 0; border-radius: var( --border-radius--medium ) var( --border-radius--medium ) 0 0; } .infobox-image td { padding: 0; } .infobox-image--light .image { background: #eaecf0; } .infobox-image--dark .image { background: #2b2f36; } .infobox-image .image:hover img { transform: scale( 1.1 ); } .infobox-image img { display: block; max-width: 100%; background: var( --background-color-quiet--hover ); } /* Neutral background for all transprent SVG */ .infobox-image img[ src$='.svg' ] { background: #eaecf0; } /* Infobox title */ .infobox .infobox-title { width: 100%; margin-top: 20px; margin-bottom: 5px; color: var( --color-base--emphasized ); font-size: var( --font-size-h3 ); line-height: var( --line-height-xs ); } /* Infobox indicator */ .infobox .infobox-indicator { margin-top: 0; padding: 0; } /* Infobox subtitle */ .infobox .infobox-subtitle { /* Cancel infobox-title bottom margin */ margin-top: -5px; margin-bottom: 5px; } .infobox .infobox-indicator th, .infobox .infobox-subtitle th { display: none; } /* Infobox header */ .infobox .infobox-header { width: 100%; padding-top: 15px; border-top: 1px solid; border-color: var( --border-color-base ); margin-top: 15px; color: var( --color-base--emphasized ); line-height: var( --line-height-xs ); font-size: 1rem; } /* Infobox value */ .infobox-data th { color: var( --color-base--subtle ); font-size: 0.8125rem; font-weight: normal; letter-spacing: 0.75px; } .infobox-data td { font-weight: 600; } .infobox-data ul, .infobox-data ol { margin-top: 0; } /* Infobox button */ .infobox .infobox-button-bar { width: 100%; padding: 0; margin-top: 25px; text-align: center; } .infobox-button-bar th { padding: 0; } /* Collapsible toggle */ .infobox tr:first-of-type .mw-collapsible-toggle { position: relative; display: none; float: none; } .infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text { position: absolute; right: 0; display: block; padding: 5px 15px; background: var( --color-destructive ); border-radius: 0 var( --border-radius--medium ); color: #fff; } .infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:hover { background: var( --color-destructive--hover ); } .infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:active { background: var( --color-destructive--active ); } .infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text { background: var( --color-primary ); } .infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:hover { background: var( --color-primary--hover ); } .infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:active { background: var( --color-primary--active ); } .infobox tr:first-of-type .mw-collapsible-toggle:before, .infobox tr:first-of-type .mw-collapsible-toggle:after { content: none; } @media only screen and ( max-width: 720px ) { .infobox { margin-right: auto; margin-left: auto; } .infobox tr:first-of-type .mw-collapsible-toggle { display: block; } } 754ac9608eeaef9b15784d251643ea8c0a01b58e Module:User error 828 65 129 128 2024-01-11T08:38:25Z EvaTheServal 2 1 revision imported Scribunto text/plain -------------------------------------------------------------------------------- -- A less intimidating version of the built-in "error()" function, to help -- editors fix their mistakes when transcluding a template. -- -- @see [[wikia:w:c:Dev:Module:User error]] for a similar module. -------------------------------------------------------------------------------- local checkType = require("libraryUtil").checkType; return function (message, ...) checkType("Module:User error", 1, message, "string"); local result = mw.text.tag( "strong", { class="error" }, "Error: " .. message ); local categories = {}; for i = 1, select("#", ...) do local category = select(i, ...); checkType("Module:User error", 1 + i, category, "string", true); if (category and category ~= "") then table.insert(categories, "[[Category:" .. category .. "]]"); end end return result .. table.concat(categories); end; a4101fc46477bcd3c5dd899b157bf34b216d820f Module:Mbox 828 66 131 130 2024-01-11T08:38:25Z EvaTheServal 2 1 revision imported Scribunto text/plain local libraryUtil = require( 'libraryUtil' ) local checkType = libraryUtil.checkType local mArguments -- lazily initialise [[Module:Arguments]] local mError -- lazily initialise [[Module:Error]] local p = {} --- Helper function to throw error -- -- @param msg string - Error message -- -- @return string - Formatted error message in wikitext local function makeWikitextError( msg ) mError = require( 'Module:Error' ) return mError.error{ message = 'Error: ' .. msg .. '.' } end function p.mbox( frame ) local args = getArgs( frame ) local title = args[1] or args[ 'title' ] local text = args[2] or args[ 'text' ] if not s then return p.makeWikitextError( 'no text specified', 'Template:Mbox#Errors', args.category ) end return p._mbox( title, text, { extraclasses = args.extraclasses, icon = args.icon } ) end function p._mbox( title, text, options ) checkType( '_mbox', 1, title, 'string' ) checkType( '_mbox', 2, text, 'string' ) checkType( '_mbox', 3, options, 'table', true ) options = options or {} local mbox = mw.html.create( 'div' ) local extraclasses if type( options.extraclasses ) == 'string' then extraclasses = options.extraclasses end mbox :attr( 'role', 'presentation' ) :addClass( 'mbox' ) :addClass( extraclasses ) local mboxTitle = mbox:tag( 'div' ):addClass( 'mbox-title' ) if options.icon and type( options.icon ) == 'string' then mboxTitle:tag( 'div' ) :addClass( 'mbox-icon metadata' ) :wikitext( '[[File:' .. options.icon .. '|14px|link=]]' ) :done() :tag( 'div' ) :wikitext( title ) else mboxTitle:wikitext( title ) end mbox:tag( 'div' ) :addClass( 'mbox-text' ) :wikitext( text ) return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Mbox/styles.css' } } .. tostring(mbox) end return p 3ac408bcf509952e70b97e64cb1062fe21f6c4bf Module:Mbox/styles.css 828 67 133 132 2024-01-11T08:38:26Z EvaTheServal 2 1 revision imported text text/plain .mbox { position: relative; display: flex; flex-direction: column; margin-top: var( --space-xs ); margin-bottom: var( --space-md ); background-color: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); color: var( --color-base--subtle ); font-size: 0.875rem; line-height: var( --line-height-xs ); } .mbox.mbox-high { /* FIXME: Update back to Citzen CSS var when patched */ background-color: rgba( 221, 51, 51, 0.1 ); } .mbox.mbox-med { /* FIXME: Update back to Citzen CSS var when patched */ background-color: rgba( 255, 204, 51, 0.1 ); } .mbox-title { display: flex; align-items: center; padding: var( --space-sm ) var( --space-md ); } .mbox-icon img { width: 14px; height: auto; margin-right: var( --space-xs ); opacity: 0.5; } .mbox-text { position: absolute; top: 100%; z-index: 10; padding: var( --space-md ); width: 100%; box-sizing: border-box; background-color: var( --color-surface-1 ); border-bottom-left-radius: var( --border-radius--medium ); border-bottom-right-radius: var( --border-radius--medium ); box-shadow: var( --box-shadow-dialog ); opacity: 0; visibility: hidden; } .mbox:hover { /* Merge with popup */ border-bottom-left-radius: 0; border-bottom-right-radius: 0; box-shadow: var( --box-shadow-dialog ); } .mbox:hover .mbox-text { opacity: 1; visibility: visible; } /* Dark mode */ html.skin-citizen-dark .mbox-icon img { filter: invert( 1 ); } 6e8c0951d8f9dcde54a751e8564916bec21071ce